Pages: [1] 2   Go Down
Author Topic: Controlador de Temperatura [Arduino + Ethernet Shield + Relays + MySQL + PHP]  (Read 11880 times)
0 Members and 1 Guest are viewing this topic.
Monterrey, MX
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Como primer proyecto me dispuse a hacer un control simple de temperatura que activa 2 relays en base a la temperatura obtenida y a su vez guarda en MySQL la temperatura para futuro procesamiento... es decir todo el control de setpoint's, horarios y demas puede ser realizado en PHP para asi dejar libre al Arduino de espacio.

Esta simple y espero a alguno de ustedes le ayude en algo.

El codigo esta hecho para un sensor DS18B20 (http://datasheets.maximintegrated.com/en/ds/DS18B20.pdf)

Requerimientos:
 - Arduino c/ Ethernet Shield
 - Sensor DS18B20 (Pero lo puedes adaptar a tus necesidades) y resistencia de 4.7k
 - 2 Relays de 5v de operación
 - Servidor PHP y MySQL
 - Tener la libreria OneWire - http://playground.arduino.cc/Learning/OneWire


Conexiones:
 - Sensor de Temperatura - Digital Pin 2
 - Relay 1 - Digital Pin 3
 - Relay 2 - Digital Pin 4



Sketch de Arduino
Code:
/*************************************************************
Project: Temperature Controller
Author: Agustin Marmolejo (Twitter @eljamz)
Date: 18-December-2012
Description: A temperature controller who save's all the data into MySQL
and from there it can activate some relays.
*************************************************************/
#include <Ethernet.h>
#include <SPI.h>
#include <OneWire.h>

//Ethernet Configuration
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xEE}; // Ethernet Shield MAC
byte ip[] = { 192,168,1,249 }; // Ethernet Shield IP
byte server[] = { 192,168,1,136 }; // Server IP

EthernetClient client;
float value;

//Settings for Relays
String location = "http://192.168.1.136/arduino_sensor.php HTTP/1.0";
char inString[32]; // string for incoming serial data
int stringPos = 0; // string index counter
boolean startRead = false; // is reading?

//Declare Relay Pinouts
int rel1Pin = 3;  // Setup Realy 1 pin
int rel2Pin = 4; // Setup Realy 2 pin

//Define where to read the Sensor
int DS18S20_Pin = 2; //DS18S20 Signal pin on digital 2

//Temperature chip i/o
OneWire ds(DS18S20_Pin); // on digital pin 2

//void setup
void setup(void) {
  Serial.begin(9600);
  Ethernet.begin(mac, ip); // Init Ethernet Shield
  pinMode(rel1Pin, OUTPUT); // Make relPin and OUTPUT
  pinMode(rel2Pin, OUTPUT); // Make relPin and OUTPUT
  delay(5000); // Wait 5 seconds to Init Program
}


//void loop
void loop(void) {
 float temperature = getTemp(); // Get the temperature from sensor and INSERT to MySQL.
 Serial.println(temperature); // print out temperature.
 delay(500); //just here to slow down the output so it is easier to read
 String pageValue = connectAndRead(); //Connect to server and get action to follow!.
 Serial.println(pageValue); //print out the findings.
 delay(500); //just here to slow down the output so it is easier to read
}


/*
FUNCTION FOR RELAYS
*/
String connectAndRead(){
  //connect to the server

  Serial.println("connecting...");

  //port 80 is typical of a www page
  if (client.connect(server, 80)) {
    Serial.println("connected");
    client.print("GET ");
    client.println(location);
    client.println();

    //Connected - Read the page
    return readPage(); //go and read the output

  }else{
    return "connection failed";
  }

}



String readPage(){
  //read the page, and capture & return everything between '<' and '>'

  stringPos = 0;
  memset( &inString, 0, 32 ); //clear inString memory

  while(true){

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

      if (c == '<' ) { //'<' is our begining character
        startRead = true; //Ready to start reading the part
      }else if(startRead){

        if(c != '>'){ //'>' is our ending character
          inString[stringPos] = c;
          stringPos ++;
        }else{
          //got what we need here! We can disconnect now
          startRead = false;
          client.stop();
          client.flush();
          Serial.println("disconnecting.");
          
          int inRel = atoi (inString);
          if (inRel == 1) {
            digitalWrite(rel1Pin, HIGH);
            digitalWrite(rel2Pin, LOW);
          } else if (inRel == 2) {
            digitalWrite(rel1Pin, LOW);
            digitalWrite(rel2Pin, HIGH);
          }
          return inString;

        }

      }
    }

  }

}



/*
FUNCTION FOR TEMPERATURE.
*/
float getTemp(){
 //returns the temperature from one DS18S20 in DEG Celsius

 byte data[12];
 byte addr[8];

 if ( !ds.search(addr)) {
   //no more sensors on chain, reset search
   ds.reset_search();
   return -1000;
 }

 if ( OneWire::crc8( addr, 7) != addr[7]) {
   Serial.println("CRC is not valid!");
   return -1000;
 }

 if ( addr[0] != 0x10 && addr[0] != 0x28) {
   Serial.print("Device is not recognized");
   return -1000;
 }

 ds.reset();
 ds.select(addr);
 ds.write(0x44,1); // start conversion, with parasite power on at the end

 byte present = ds.reset();
 ds.select(addr);  
 ds.write(0xBE); // Read Scratchpad

 
 for (int i = 0; i < 9; i++) { // we need 9 bytes
  data[i] = ds.read();
 }
 
 ds.reset_search();
 
 byte MSB = data[1];
 byte LSB = data[0];

 float tempRead = ((MSB << 8) | LSB); //using two's compliment
 float TemperatureSum = tempRead / 16;
 
 //Display in Serial Monitor
 Serial.print(TemperatureSum); //Return temperature to Monitor
 Serial.println(" Celsius");
 
 //Save Temperature to MySQL
  Serial.println("Connecting...");

  if (client.connect(server, 80)>0) {  // Connect to server
    client.print("GET /arduino_sensor.php?type=Celsius&value="); // Send the DATA with GET
    client.print(TemperatureSum);
    client.println(" HTTP/1.0");
    client.println("User-Agent: Arduino 1.0");
    client.println();
    Serial.println("Connected");
  }
  else
  {
    Serial.println("Connection FAIL");
  }
  if (client.connected()) {}
  else {
    Serial.println("Disconnected!");
  }
  client.stop();
  client.flush();
}

arduino_sensor.php
Code:
<?php
include('db.php');
//Get parameter sended by Arduino.
$type $_GET["type"];
$value $_GET["value"];


// Validate parameters if any and INSERT.
if (($type != "") && ($value != "")) {
mysql_query("INSERT INTO sensor (date, type, value) values (NOW(),'$type','$value')");
} else {

//If no parameters run script for RELAYS.
$result mysql_query("SELECT value FROM sensor ORDER BY date DESC LIMIT 1");
while(
$row mysql_fetch_array($result))
  {
$value $row['value'];
$value = (int)$value;
  }
}

if (
$value >= 28) { //this could be changed to anything, if you return <1> start Relay 1 in PIN3 and <2> start your second Relay in PIN 4.
echo "<1>";
} else {
echo "<2>";
}


mysql_close($con);
?>


db.php
Code:
<?php

$con 
mysql_connect("localhost","root","");
if (!$con){
die('Connection fail: ' mysql_error());
}
mysql_select_db("arduino"$con);
?>

MySQL Create Code
Code:
CREATE TABLE `sensor` (
`id` INT(10) NOT NULL AUTO_INCREMENT,
`date` DATETIME NOT NULL,
`type` VARCHAR(100) NOT NULL COLLATE 'latin1_spanish_ci',
`value` FLOAT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `id` (`id`)
)
COLLATE='latin1_spanish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=0;


Espero les sirva, saludos!
« Last Edit: December 18, 2012, 03:26:46 am by eljamz » Logged

You can't control what you can't measure!

COM22
Offline Offline
God Member
*****
Karma: 6
Posts: 702
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Muy buen trabajo!

Me gustaría hacerte una recomendación en el código arduino_sensor.php, ya que es vulnerable a una inyección SQL y un graciosillo que encuentre la pagina puede fastidiarte la base de datos.

Simplemente es añadir mysql_real_escape_string() a las variables que van a interactuar con la base de datos para evitar una posible intrusión.

Quote
mysql_query("INSERT INTO sensor (date, type, value) values (NOW(),'mysql_real_escape_string($type)','mysql_real_escape_string($value)')");


Un saludo  smiley-wink
Logged


0
Offline Offline
Edison Member
*
Karma: 17
Posts: 1413
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

estupendo aporte !!

hace tiempo que tengo este mismo post pendiente de compartir con la comunidad, me lo has ahorrado jeje

luego lo pruebo y comento si algo va mal pero tiene muy buena pinta.
Logged

* Si preguntas, pon el código de tu programa, hace mucho mas fácil ayudarte. Y me ahorro un mensaje pidiendo que lo hagas.
* Si consigues solucionar tu problema, dedica unos minutos a explicar en tu post como lo conseguiste para beneficio de todos.
* Cambia el 'Subject' de tu hilo y añade 'SOLUCIONADO' cuando hayas llegado a una solución al problema que planteaste.
* Utiliza un 'Subject' para tu hilo que explique de que va el hilo.
Si estas empezando:
* Comienza a usar Arduino
* Guías de iniciación a Arduino
* Ejemplos
* Referencia del Lenguaje
* Conceptos básicos
Guia de usuario de arduino
Tutoriales en Ingles
Si necesitas que alguien te escriba el código: http://www.freelancer.com/  o esta  http://www.guru.com/

Monterrey, MX
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Gracias por sus comentarios, con respecto al Inyección SQL, Se me ocurre agregarle a las cadenas un user y una pwd, y validar de esta manera, digo ya para que sepan también el usuario y contraseña estará medio difícil supongo!

Esto además de poner este comando para limpiar las variables...


Saludos!
Logged

You can't control what you can't measure!

COM22
Offline Offline
God Member
*****
Karma: 6
Posts: 702
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Si quieres seguridad a tope usa md5 en el servidor arduino y en el script php. Es como funcionan las API simple y muy eficaz.

Por ejemplo en el servidor arduino que te genere el md5 de la string de temp seguido de tu key (tempKEY). Se lo envías al php como .php?temp=22&md5=(lo que genere arduino), entonces con la misma key que la de arduino y la temp que recibes en el php vuelves a generar el md5 y los comparas, que son iguales sigues adelante que no puede ser una intrusión.

Un saludo!
Logged


Offline Offline
Jr. Member
**
Karma: 3
Posts: 88
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Buen trabajo, este me lo guardo en la carpeta de recortes.
Y buen apunte de JRodrigo.

Muy buen trabajo!

Me gustaría hacerte una recomendación en el código arduino_sensor.php, ya que es vulnerable a una inyección SQL y un graciosillo que encuentre la pagina puede fastidiarte la base de datos.

Simplemente es añadir mysql_real_escape_string() a las variables que van a interactuar con la base de datos para evitar una posible intrusión.

Quote
mysql_query("INSERT INTO sensor (date, type, value) values (NOW(),'mysql_real_escape_string($type)','mysql_real_escape_string($value)')");


Un saludo  smiley-wink
Logged

Monterrey, MX
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Si quieres seguridad a tope usa md5 en el servidor arduino y en el script php. Es como funcionan las API simple y muy eficaz.

Por ejemplo en el servidor arduino que te genere el md5 de la string de temp seguido de tu key (tempKEY). Se lo envías al php como .php?temp=22&md5=(lo que genere arduino), entonces con la misma key que la de arduino y la temp que recibes en el php vuelves a generar el md5 y los comparas, que son iguales sigues adelante que no puede ser una intrusión.

Un saludo!

Creo que con el puro md5(tempKEY); es suficiente no?, digo a final de cuentas la idea es que no se sepan la tempkey... y el valor de la temperatura es irrelevante una vez que adivinen el (tempKEY)



Logged

You can't control what you can't measure!

0
Offline Offline
Edison Member
*
Karma: 16
Posts: 1579
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

He añadido el post en http://playground.arduino.cc//Es/FAQ

Saludos y gracias,


Igor
Logged


COM22
Offline Offline
God Member
*****
Karma: 6
Posts: 702
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Creo que con el puro md5(tempKEY); es suficiente no?, digo a final de cuentas la idea es que no se sepan la tempkey... y el valor de la temperatura es irrelevante una vez que adivinen el (tempKEY)

Lo del md5 era una idea por si te podía interesar, es también valida tu idea de utilizar un usuario con su contraseña, ya que pienso que nadie se va a dedicar a meterte datos falsos (alguien que se aburra mucho puede que si jajjaja), la única brecha de seguridad bastante grave era al introducir los datos en la DB pero lo arreglas con la función mysql_real_escape_string() y listo!
Logged


Monterrey, MX
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

He añadido el post en http://playground.arduino.cc//Es/FAQ

Saludos y gracias,


Igor
Gracias a ti! es un honor aparecer ahi!


Lo del md5 era una idea por si te podía interesar, es también valida tu idea de utilizar un usuario con su contraseña, ya que pienso que nadie se va a dedicar a meterte datos falsos (alguien que se aburra mucho puede que si jajjaja), la única brecha de seguridad bastante grave era al introducir los datos en la DB pero lo arreglas con la función mysql_real_escape_string() y listo!
De hecho tienes razon, pero lo del MD5 tempkey tambien es una "buena" practica, lo ideal seria utilizar una session, y esto es posible pero nos quitaria mucho espacio... lo que podemos hacer es:

Como ya sabemos la direccion IP del arduino, podemos desde PHP saber el IP del cliente, y entonces limitar a que solo el arduino tenga acceso...

Agregar esto en "arduino_sensor.php"
Code:
<?php
$arduino_ip 
"192.168.1.1";
$client_ip = @$REMOTE_ADDR

if (
$arduino_ip == $client_ip) {

EL CODIGO AQUI

} else {
echo 
"No estas autorizado para usar este sitio";
}
?>

« Last Edit: December 20, 2012, 04:33:05 pm by eljamz » Logged

You can't control what you can't measure!

0
Offline Offline
Edison Member
*
Karma: 17
Posts: 1413
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

creo que deberia de ser
Code:
$_SERVER["REMOTE_ADDR"]
al menos en mi servidor remoto.

Lo malo es que si se reinicia el router y cambia la ip, ya no funcionara.

Por supuesto me refiero si el servidor esta fuera de la red de casa.
Logged

* Si preguntas, pon el código de tu programa, hace mucho mas fácil ayudarte. Y me ahorro un mensaje pidiendo que lo hagas.
* Si consigues solucionar tu problema, dedica unos minutos a explicar en tu post como lo conseguiste para beneficio de todos.
* Cambia el 'Subject' de tu hilo y añade 'SOLUCIONADO' cuando hayas llegado a una solución al problema que planteaste.
* Utiliza un 'Subject' para tu hilo que explique de que va el hilo.
Si estas empezando:
* Comienza a usar Arduino
* Guías de iniciación a Arduino
* Ejemplos
* Referencia del Lenguaje
* Conceptos básicos
Guia de usuario de arduino
Tutoriales en Ingles
Si necesitas que alguien te escriba el código: http://www.freelancer.com/  o esta  http://www.guru.com/

Monterrey, MX
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Justo eso quise decir
Red Local:
Code:
$ip = $_SERVER["REMOTE_ADDR"];
Si estas dentro de la red el IP esta definido, y si estas trabajando sobre internet puedes utilizar un "No-IP.org" o "DynDNS" asi tu ip publica si cambia el PHP la resuelve en automatico...

Code:
$ip = gethostbyname("user.no-ip.org");

Saludos!
Logged

You can't control what you can't measure!

Offline Offline
Full Member
***
Karma: 1
Posts: 208
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Justo eso quise decir
Red Local:
Code:
$ip = $_SERVER["REMOTE_ADDR"];
Si estas dentro de la red el IP esta definido, y si estas trabajando sobre internet puedes utilizar un "No-IP.org" o "DynDNS" asi tu ip publica si cambia el PHP la resuelve en automatico...

Code:
$ip = gethostbyname("user.no-ip.org");


Es mas, algunos routers tienen la opcion de añadirle la cuenta y que sea el propio router el que la actualice automaticamente.
Saludos!
Logged


Monterrey, MX
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Es mas, algunos routers tienen la opcion de añadirle la cuenta y que sea el propio router el que la actualice automaticamente.
Saludos!

Si! creo que ya la mayoria lo tiene como "default" solo busquen DynDNS y ahi apareceran varios servicios y ya lo configuran, esto para poder actualizar el IP en automatico.
Logged

You can't control what you can't measure!

0
Offline Offline
Edison Member
*
Karma: 17
Posts: 1413
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Up
Logged

* Si preguntas, pon el código de tu programa, hace mucho mas fácil ayudarte. Y me ahorro un mensaje pidiendo que lo hagas.
* Si consigues solucionar tu problema, dedica unos minutos a explicar en tu post como lo conseguiste para beneficio de todos.
* Cambia el 'Subject' de tu hilo y añade 'SOLUCIONADO' cuando hayas llegado a una solución al problema que planteaste.
* Utiliza un 'Subject' para tu hilo que explique de que va el hilo.
Si estas empezando:
* Comienza a usar Arduino
* Guías de iniciación a Arduino
* Ejemplos
* Referencia del Lenguaje
* Conceptos básicos
Guia de usuario de arduino
Tutoriales en Ingles
Si necesitas que alguien te escriba el código: http://www.freelancer.com/  o esta  http://www.guru.com/

Pages: [1] 2   Go Up
Jump to: