domingo, 30 de diciembre de 2018

Servidor web con ESP8266

Hoy les traigo la continuación del servidor simple, la idea es poder interactuar con el micro a través de una interfaz web. En este ejemplo vamos a encender y apagar el led del ESP8266 de forma remota, también se pueden agregar hojas de estilo y me imagino que también se puede agregar código en javaScript (después de todo lo que hay que hacer es mandar texto al navegador para que lo interprete), el único cuidado que hay que tener es escribir el html, el css y lo que necesiten uno a continuación del otro.

Para recuperar variables de la página web hay que hacerlo de la siguiente forma:

  servidorweb.on("/", []()
  {
    String estado = servidorweb.arg("estado");
    if(estado == "ON")
    {
      digitalWrite(2, LOW);
    }
    else if(estado == "OFF")
    {
      digitalWrite(2, HIGH);
    }
    servidorweb.send(200, "text/html", HTMLpage);
  });

con el ".arg()" recuperamos el valor de la variable que pongamos entre paréntesis, luego podremos trabajar en función de eso.

El código total quedaría de la siguente forma:


#include <ESP8266WiFi.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>

ESP8266WebServer servidorweb(80);

const char* red = "red"/*ingrese aquí el nombre de id*/;
const char* contra = "contra"/*ingrese aquí la contraseña*/;
String HTMLpage =

  "<!DOCTYPEhtml>"
  "<html>"
    "<head>"
      "<title>"
        "Tutorial de servidor web"
      "</title>"
    "</head>"
    "<h3>"
      "Esto es un servidor web (de ejemplo)<br>"
      " con el micro ESP8266 para controlar<br>"
      " el led integrado en la placa."
    "</h3>"
    "<form action=\"/\" method=\"post\">"
      "<td><button name=\"estado\" type=\"submit\" class = \"button\" value=\"ON\">ON</button></td>"
      "<td><button name=\"estado\" type=\"submit\" class = \"button\" value=\"OFF\">OFF</button></td>"
    "</form>"
  "<html>";

void setup() {

  Serial.begin(115200);
  pinMode(2, OUTPUT);

  WiFi.begin(red, contra);

  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("");
  Serial.print("Conectado a");
  Serial.println(red);
  Serial.print("Dirección IP:");
  Serial.println(WiFi.localIP());
  
  servidorweb.on("/", []()
  {
    String estado = servidorweb.arg("estado");
    if(estado == "ON")
    {
      digitalWrite(2, LOW);
    }
    else if(estado == "OFF")
    {
      digitalWrite(2, HIGH);
    }
    servidorweb.send(200, "text/html", HTMLpage);
  });

  servidorweb.begin();
}

void loop() {
  
  servidorweb.handleClient();
  
}

Recordemos que la página va a estar montada sobre la dirección ip 192.168.4.1, por lo que hay que ingresar ahí para ver la página. Si bien la página y el código son muy sencillos, como mencioné antes, se puede agregar javaScript y css para que la página sea más interesante, pero hay que tener en cuenta que si queremos agregar librerías o frameworks de JS la memoria del microcontrolador va a empezar a escasear. En teoría se podría agregar una memoria externa (ej. una microSD) para almacenar la página web con todas las librerías y demás. A continuación les dejo cómo luce la página que acabamos de hacer.


Básicamente cuando presionamos los botones se "manda" al argumento "estado" el valor "ON" u "OFF" el cuál el servidor va a procesar para prender o apagar el led. Como los estados del ESP8266 están negados el estado low va a encender el led y el high lo va a apagar.

domingo, 23 de diciembre de 2018

Módulo GPS

Hoy les traigo el módulo gps neo6m.
Primero hablemos sobre lo que es el gps, es un sistema de posicionamiento global (uno de varios), el cual está compuesto por una costelación de satélites que emiten señales con ciertos datos, como por ejemplo la hora. Luego estos datos se procesan, conociendo la identifiación de cada satélite, la hora, la intensidad de la señal recibida y algunas cosas más, se puede conocer la posición del dispositivo que recibe estas señales; esto se logra con trigonometría, por lo que para conocer la posición exacta de algo como mínimo se van a necesitar tres satélites, y cuantos más haya el sistema va a ser más preciso.
El gps utiliza longitud y latitud y divide a la tierra en 4 partes, cada una de 90 grados, si obvservamos un mapa:



podremos ver que estas divisiones ya existen hace tiempo, por lo que agregando unos cuantos ceros detrás de la coma obtendremos distancias muy precisas, cada grado corresponde a 111,1 km (es periódico ese valor, es decir que tiene infinitos unos detrás de la coma) y por ejemplo un metro son 0,000009 grados, cien metros son 0,0009 grados y así sucesivamente. Cuántos más ceros haya detrás de la coma, más precisas van a ser las mediciones.
Para comenzar a utilizar el módulo, primero vamos a utilizar un programa que nos permita utilizar un arduino como un puente serie entre el dispositivo y la computadora (básicamente generamos un puerto serie en dos pines del arduino, en el cuál vamos a conectar el gps, y luego conectamos el arduino a la computadora, no hay que conectar el módulo de gps a los pines 0 y 1), lo que nos va a mandar el gps va a ser algo similar a lo siguiente:

$GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62
$GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68
225446 Time of fix 22:54:46 UTC
A Navigation receiver warning (A = OK, V = warning)
4916.45,N Latitude 49 deg. 16.45 min North = 49°16'45''
12311.12,W Longitude 123 deg. 11.12 min West = 123°11'12''
000.5 Speed over ground, Knots
054.7 Course Made Good, True
191194 Date of fix 19 November 1994
020.3,E Magnetic variation 20.3 deg East
*68 mandatory checksum

Como hay un montón de datos, lo más fácil es utilizar una librería para interpretarlos, puesto que ya alguien se encargó de depurar esos datos y fue lo suficientemente gentil para compartirlo con el mundo vamos a utilizarla, se llama tinyGPS, vamos a utilizar uno de los tres ejemplos:

#include <SoftwareSerial.h>
#include <TinyGPS.h>

/* 
   This sample code demonstrates the normal use of a TinyGPS object.
   It requires the use of SoftwareSerial, and assumes that you have a
   4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/

TinyGPS gps;
SoftwareSerial ss(4, 3);

void setup()
{
  Serial.begin(115200);
  ss.begin(4800);
  
  Serial.print("Simple TinyGPS library v. "); Serial.println(TinyGPS::library_version());
  Serial.println("by Mikal Hart");
  Serial.println();
}

void loop()
{
  bool newData = false;
  unsigned long chars;
  unsigned short sentences, failed;

  // For one second we parse GPS data and report some key values
  for (unsigned long start = millis(); millis() - start < 1000;)
  {
    while (ss.available())
    {
      char c = ss.read();
      // Serial.write(c); // uncomment this line if you want to see the GPS data flowing
      if (gps.encode(c)) // Did a new valid sentence come in?
        newData = true;
    }
  }

  if (newData)
  {
    float flat, flon;
    unsigned long age;
    gps.f_get_position(&flat, &flon, &age);
    Serial.print("LAT=");
    Serial.print(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
    Serial.print(" LON=");
    Serial.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
    Serial.print(" SAT=");
    Serial.print(gps.satellites() == TinyGPS::GPS_INVALID_SATELLITES ? 0 : gps.satellites());
    Serial.print(" PREC=");
    Serial.print(gps.hdop() == TinyGPS::GPS_INVALID_HDOP ? 0 : gps.hdop());
  }
 
  gps.stats(&chars, &sentences, &failed);
  Serial.print(" CHARS=");
  Serial.print(chars);
  Serial.print(" SENTENCES=");
  Serial.print(sentences);
  Serial.print(" CSUM ERR=");
  Serial.println(failed);
  if (chars == 0)
  {
    Serial.println("** No characters received from GPS: check wiring **");
  }
}

Este ejemplo nos entrega los datos separados, por lo que podríamos implementarlo en cualquier proyecto que necesite gps.
Hay otra librería llamada tinyGPS plus, del mismo creador, que en teoría nos ofrece más cosas, como por ejemplo usar el glonass (el análogo ruso del gps).

domingo, 16 de diciembre de 2018

ESP8266 y ILI9341

Hoy les traigo cómo utilizar el display gráfico (y a color!) basado en el driver ILI9341, el display gráfico en cuestión es uno de 2,2" y cuenta con un lector de memorias SD (que de momento no vamos a utilizar). Se maneja bajo el protocolo de comunicación SPI. La diferencia más notoria entre este display y el SPFD5408 es la velocidad con que se maneja, si bien el SPFD5408, al igual que el ILI9341, admite el uso de SPI como protocolo de comunicación lo que pude ver es que la velocidad con la que se refresca la pantalla es muchísimo más alta. Otra clara ventaja es que usa menos pines (aunque no probé el SPI de la SPFD5408, en su configuración "base" de hardware la cantidad de pines es menor), aunque no todo son ventajas, el ILI9341 no cuenta con una una entrada táctil, por lo que debemos desarrollar algo para que poder interactuar con el micro de ser necesario.


Como vamos a utilizar el ESP8266 para usar con este módulo vamos a necesitar una librería especial para este micro. El mapa de los pines utilizados es el siguiente:

DISPLAY        NodeMCU

SDO/MISO      D6 (no conecta si no se "lee" el display)
LED                 VIN (or 5V, see below)
SCK                 D5
SDI/MOSI       D7
DC (RS/AO)   D3
RESET            D4 (o RST, depende de la configuración)
CS                   D8 (o RST, depende de la configuración)
GND               GND (0V)
VCC               5V or 3.3V

Como es muy sencillo utilizar este display con los códigos de ejemplo que vienen con la librería debería bastar para que puedan entender la base. De todas formas les comento que esta librería posee un archivo que sirve para realizar algunas configuraciones, como por ejemplo:

*qué driver tiene la pantalla (en nuestro caso es la ILI9341)
*configuraciones especiales para ciertos drivers
*modificar los pines que se utilizan para la comunicación (los pines que se pueden evitar usar)
*qué fuentes se utilizan
*la frecuencia del SPI

Hay bastantes configuraciones disponibles con esta librería para adaptarla al proyecto que deseemos (más que nada para la optimización de la memoria del microcontrolador, y velocidad de la pantalla).

Algunos de los comandos útiles para el uso de este display son los siguientes:

  • drawPixel(x, y, color): este comando dibuja un pixel en la posición X e Y (que son del tipo UINT) y de color especificado en esa variable (también UINT, el color va a ser de 16 bits, 5 rojos, 6 verdes y 5 azules, utiliza la codificación RGB565 y se pueden generar con este programita)
  • fillScreen(color): útil para llenar toda la pantalla con un color.
  • drawLine(x0, y0, x1, y1, color): dibuja una línea entre los puntos (x0, y0) y (x1, y1) del color especificado.
  • draw/fillRect(x, y, medidaX, medidaY, color): dibuja un rectángulo con punto de inicio en (x, y) y de medidas de medidaX y medidaY, si es draw lo dibuja sin fondo, y si es fill es con fondo, el color hace referencia al color de lo que dibuja.
  • draw/fillRect(x, y, r, color): dibuja un círculo con centro en (x, y) de radio r y con el color pasa lo mismos que con el punto anterior.
  • drawString(texto, x, y, fuente): escribe el texto con puntos iniciales en (x, y) y con una fuente que como un valor genérico podría ser el 2.

Hay una lista muy larga de comandos que habría que explicar uno a uno, pero con los explicados arriba debería bastar para entender la dinámica básica del funcionamiento de la librería.

domingo, 9 de diciembre de 2018

Alarma de gas y humo con gsm

Antes que nada, no me hago cargo de cómo se use la información de este post, es meramente educativa.

Hoy les traigo un código que tengo hace bastante (lamentablemente no tengo fotos del sensor y demás), funciona con un módulo detector de gas y humo (de la serie mq-xxx), el módulo gsm800 y un arduino nano. El código es sencillo, cuando se lee que la cantidad de gas en el aire supera cierto valor, el micro activa una alarma visual y sonora, además de desconectar un pin (esto es porque la idea era usarlo con una electroválvula controlada con un relé, por lo que el pin que se desconecta debería ir al relé) y luego de un tiempo (10 segundos) si se sigue detectando gas o humo se envía un mensaje de texto al número programado.
Este equipo está diseñado para bajos caudales de gas (de humo no porque no existe riesgo de que explote e inutilice el equipo), por ejemplo una hornalla o en el caso más extremos una estufa.

Obviamente este equipo no está destinado a armarse porque tiene muchísimas fallas, desde un principio no tiene ninguna redundancia, por lo que si falla algo no hay una segunda instancia verificando.

A continuación les dejo el código:


#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX
long tiempo;

int pin_led_verm = 3; //led indicador de electrovalvula de gas conectada
int pin_buzzer = 2;   //sonido y señalización luminosa indicadora de alarma
int pin_d0 = 4;
int pin_a0 = A7;
int nivel_sensor = 100;

void setup ()
{
  pinMode(pin_d0, INPUT);
  pinMode(pin_a0, INPUT);
  pinMode(pin_led_verm, OUTPUT);
  pinMode(pin_buzzer, OUTPUT);
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);
  Serial.begin(9600);

//------------------------------------------------------//  

  mySerial.begin(9600);
  delay(20000);
  Serial.println("encendido");
  comando ("at");
  delay(20000);
  comando ("ATI+CMEE=2");         //pone el modo de los errores en texto
  comando ("at");                 //
  comando ("ati");                //obtiene nombre del módulo y versión
  comando ("at+ccid");            //obtiene el número de la tarjeta sim
  comando ("at+cbc");             //obtiene el estado de la batería
  comando ("at+csq");             //obtiene la fuerza de la señal
  comando ("at+cops?");           //obtiene la conección de la red
  mySerial.print("AT+CMGF=1\r");  //modo texto
  Serial.println("fin del informe");

}

void loop ()
{
  int valor_digital = digitalRead(pin_d0);
  int valor_analogico = analogRead(pin_a0);
  Serial.print("valor digital: ");
  Serial.print(valor_digital);
  Serial.print(" valor analogico: ");
  Serial.println(valor_analogico);
  if(valor_analogico > nivel_sensor)
  {
    digitalWrite(pin_led_verm, LOW);  //corta electroválvula de gas
    digitalWrite(pin_buzzer, HIGH);   //suena alarma visual y audible

    /*
     * verifico que haya durante 10 segundos gas antes de enviar
     * el mensaje.
     */
    for(int i = 0; i < 11; i++)
    {
      digitalWrite(13, LOW);
      if(i == 10 && analogRead(pin_a0) > nivel_sensor)
      {
        digitalWrite(13, HIGH);
        Serial.print("mandando mensaje");
        mensaje ();
        Serial.print("mensaje enviado");
      }
      delay(800);
    }
  }
  else
  {
    digitalWrite(pin_led_verm, HIGH); //válvula conectada
    digitalWrite(pin_buzzer, LOW); //Sonido y led silenciado
  }
}

void mensaje ()
{
  /*
   * si se quieren agregar varios números hay que
   * hacerlo en la variable numero y separarlos por
   * comas.
   */
  char* numero[]={"54911*******"};
  
  Serial.println("envio de sms");

  delay(200);

  for(int i = 0; i < sizeof(numero); i++)
  {
    Serial.println(i);
    delay(200);
    mySerial.print ("AT+CMGS=\"+");
    mySerial.print (numero[i]);
    mySerial.println ("\"");
    delay(200);
    mySerial.write('\r');
    delay(200);
    mySerial.print("alarma de gas o humo");
    delay(300);
    mySerial.write(0x1A);
    delay(7000);
  }
  Serial.println("fin del informe");
}

void comando (char com[40])
{
  mySerial.write(com);
  mySerial.write('\r');
  delay(200);
  while (mySerial.available())
  {
    Serial.write(mySerial.read());
  }
}

domingo, 2 de diciembre de 2018

manejo de potencia con relé de estado sólido

Bueno, siguiendo con el tema de la semana pasada, hoy voy a hablarles sobre cómo manejar potencia utilizando un relé de estado sólido. Para empezar el modelo de relé que vamos a ver es el S202S02 de la empresa sharp, este relé es capaz de conducir hasta 8 amperes y 600v y la parte de potencia está aislada de la de control (al igual que el moc3021 está optoacoplado), por lo que para controlarlo hay que encender o apagar un led. Un circuito de aplicación sería el siguiente, en donde la parte de control está manejada por un microcontrolador (el único circuito que pude encontrar fue el siguiente, lamentablemente está en inglés y fue sacado de la hoja de datos):



La ventaja de este componente por sobre un relé convencional es que el tiempo de conmutación es muchísimo más alto, al no ser mecánico se reduce el ruido (tanto eléctrico como mecánico), no es necesario aumentar la tensión para controlarlo (esto lo destaco porque si bien existen comercialmente los relés con un control de 5v o 3,3v no se consigue tan fácilmente, la mayoría son de 12v) y la corriente necesaria para excitarlo puede ser entregada por casi cualquier microcontrolador. Como desventaja tiene que es más delicado (una variación de 1v en la entrada puede quemar la etapa de control aunque hay modelos que admiten un rango de tensiones ridículas) y maneja menos potencia (incluso con disipador).

Este componente es capaz de manejar unos decentes 3,75A a -25ºC de temperatura ambiente, y 2,5A a 25ºC, el valor de la corriente disminuye linealmente hasta alcanzar los 100ºC de temperatura ambiente donde sólo puede conducir unos 0,75A. Estos valores cambian drásticamente cuando se agrega un disipador (de dimensiones de 50 x 50 x 2 mm de aluminio) en donde puede soportar hasta 8A a -25ºC, unos 5,5A a 25ºC y 1,5A a 100ºC. Mientras más grande sea el disipador (hasta un máximo de 200 x 200 x 2 mm de aluminio) va a poder conducir 8A a temperaturas de ambiente más alta. Sin embargo para poder realizar un buen diseño hay que revisar la hoja de datos.

domingo, 25 de noviembre de 2018

Manejo de potencia con TRIAC

Hola a todos, hoy les traigo sobre el manejo de potencia con un triac. Esto lo vamos a hacer con los componentes bt137 y moc3021. El bt137 es el triac y el encargado de manejar la potencia, para este ejemplo (y para cuidar al componente) vamos a utilizar disipador.

En cuanto al moc3021 es el que se va a encargar de disparar el triac. Este componente aisla la parte de potencia con la de control (está optoacoplado) y nos permite operar de forma "segura" con un microcontrolador. Básicamente el moc3021 es un diac controlado por luz, un "fotodiac".

El circuito que vamos a utilizar es el siguiente:



Este circuito nos va a permitir manejar potencia desde un microcontrolador, y variando el pulso de disparo antes o después vamos a poder variar en qué momento comienza a conducir el triac y por lo tanto cuánta potencia entrega. Si queremos utilizarlo sin disipador hay que tener en cuenta cuánta corriente vamos a controlar, por ejemplo, si queremos utilizarlo con una carga de 10W, vamos a tener que:

10W / 220v = 0,0455A

Y como la caída de tensión sobre el componente es de 1,65v constantes, entonces vamos a tener:

1,65v * 0,0455A = 0,0751W

O lo que es lo mismo 75mW. Para ese tipo de encapsulado (TO220) la potencia máxima que puede disipar es de 2,5W que nos da una corriente máxima para este triac de:

2,5W / 1.65v = 1,52 A

Pero lo más seguro es que si hacemos conducir 1,52A, sin ningún tipo de disipador, el componente se queme de inmediato (y en caso de que no se queme, recomiendo no tocarlo). Como regla general hay que tomar la mitad (o incluso un tercio) del valor máximo como el valor a utilizar, es decir que si este componente puede disipar hasta 2,5W entonces como máximo deberíamos tomar entre 0,8W y 1,25W (yo usaría el 0,8W como máximo), a continuación les dejo una tabla aproximada de las potencias máximas que pueden disipar los distintos encapsulados:


TO5/TO32 0,8W
TO202 1,7W
TO220 2,5W
TO3            3,5W

Estos valores son muchas veces para casos ideales, por lo que yo tomaría los siguientes valores (para usar sin disipador)

TO5/TO32   0,3W
TO202 0.65W
TO220 0.8W
TO3            1.2W

Esa es la máxima potencia que puede disipar cada tipo de encapsulado y para tener una idea aproximada de como dimensionar nuestros circuitos (si es necesario que lleven disipador o no). Luego el próximo dato que hay que ver es cuál es la máxima corriente que es capaz de conducir el modelo de nuestro componente, para el caso del bt137 es de 8A y dependiendo del modelo va a poder conducir hasta un máximo de 600v, por lo que si queremos hacer pasar eso, nuestro componente va a tener que disipar:

1.65v * 8A = 13.2W (el 1,65v es la tensión que cae en el componente)

que es casi 17 veces más de lo que está preparado el encapsulado, por lo que hay que usar un disipador.

domingo, 18 de noviembre de 2018

estación meteorológica con base de datos

Hoy les traigo como hacer que la estación meteorológica almacene los datos con una base de datos.

Esto va a ser muy similar a lo ya implementado con el ejemplo de la base de datos, pero la idea es tener los siguientes campos:

temperatura
humedad
lux
hora
fecha
localización

Estos datos nos van a permitir discriminar la ubicación de las lecturas. Entonces vamos a crear una nueva base de datos, con la ubicación en donde querramos y vamos a poner el nodo inject con lo siguiente en el tópico

CREATE TABLE clima(temperatura NUMERIC, humedad NUMERIC, lux NUMERIC, hora TIME, fecha DATE, localizacion TEXT)

Una vez creada la base de datos ese módulo de injección ya no nos sirve para nada, por lo que podemos eliminar el nodo (sólo para no tener cosas inútiles en la pantalla). Luego vamos a poner un nodo de función en el cuál vamos a poner el siguiente código (para que funcione de la mejor forma posible vamos a modificar el código del esp para que mande todos los mensajes con el formato: temperatura&&&humedad&&&lux&&&localizacion, el dato de la localización lo vamos a embeber en el código de forma manual (sin gps) para no complicar las cosas, quizá algún día hagamos algo similar):


var mensaje = msg.payload.split("&&&");
if((mensaje[0] !== "nan") && (mensaje[1] !== "nan") && (mensaje[2] !== "nan"))
{
    msg.payload = null;
    msg.topic = "INSERT INTO clima(temperatura, humedad, lux) VALUES(" + mensaje[0] + "," + mensaje[1] + "," + mensaje[2] + ")";
    return msg
}
return null;



Que nos va a permitir administrar la información y generar el comando necesario para poder guardarlo con la base de datos, y la segunda parte nos va a permitir graficar todos los datos en un mismo gráfico (queda muy bien, además se van a poder comparar los datos más directamente).


En la imágen está el flujo de ejemplo (en realidad se podría usar, y en lugar del nodo de inyección habría que poner un nodo de MQTT que nos entregue los datos de los sensores), en la cuál concentramos todos los datos en una sola gráfica, y realizando ciertos ajustes podríamos ver qué datos representa cada color o incluso cambiar el color de cada dato.

Para completar el proyecto habría que modificar el código de nuestro micro para que nos mande los lúmenes y los datos de la ubicación. Como no vamos a agregarle datos de ubicación reales (todavía no me meto en el mundo del gps), solo vamos a utilizar identificadores del estilo "casa" o alguna otra cosa. En cuanto a los lúmenes, sólo hay que realizar una lectura analógica siguiendo esta librería. El código final es el siguiente:

/*
 * Este programa es una estación meteorológica que verifica los niveles de 
 * temperatura y humedad del ambiente con el sensor DTH11. Se alimenta con 
 * una celda fotovoltáica, y posee un cargador de baterías y alimentación 
 * para el equipo.
 */


#include <ESP8266WiFi.h>
#include <PubSubClient.h>

//---------------------------------------------------------------------------

#include "DHT.h"

#define DHTPIN            5         // Pin de datos
#define DHTTYPE           DHT11     // DHT 11

// El tercer parámetro va en función de la velocidad
// del microprocesador, cuanto más rápido sea, más 
// grande el valor (6 es para un micro de 16Mhz).

DHT dht(DHTPIN, DHTTYPE, 11);

//---------------------------------------------------------------------------

// verificar el ejemplo de la librería para saber como 
//conectar la resistencia.
// quizá lo mejor sea poner una resistencia de 10k.
#include <LightDependentResistor.h>

#define OTHER_RESISTOR 3300 //ohms
#define USED_PIN A0
#define USED_PHOTOCELL LightDependentResistor::GL5528

// Create a GL5528 photocell instance (on A0 pin)
LightDependentResistor photocell(USED_PIN, OTHER_RESISTOR, USED_PHOTOCELL);

//---------------------------------------------------------------------------

// Las siguientes tres constantes definen, nombre
// de red wifi y su contraseña.

const char* ssid = "NombreRed";
const char* password = "Contraseña";
const char* mqtt_server = "DirecciónServidor";

// Acá definimos los pines.

const int d1 = 5, d2 = 4, d3 = 0, pin_led = 2;

long tiempo = 0;

// A continuación declaramos el nombre del cliente 
// que se va a conectar.

WiFiClient espClient;
PubSubClient client(espClient);

// En esta variable se almacena el mensaje recibido
// notar que tiene un máximo de 50 (en realidad son
// 49) caracteres.

char msg[50];

void setup() {
  pinMode(pin_led, OUTPUT);   //Pin del LED 2
  digitalWrite(pin_led, LOW);
  pinMode(d1, INPUT);         //Pin D1
  pinMode(d2, INPUT);         //Pin D2
  pinMode(d3, INPUT);         //Pin D3
  
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);

  dht.begin();
}

void setup_wifi() {

    Serial.println();
    Serial.print("Conectando a: ");
    Serial.println(ssid);
  
    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) 
    {
      delay(500);
      Serial.print(".");
    }
  
    digitalWrite(pin_led, HIGH);
  
    Serial.println("");
    Serial.println("WiFi conectado");
    Serial.println("IP: ");
    Serial.println(WiFi.localIP());

}

// En esta función se administra la llegada de 
// mensajes, nos avisa en qué tópico llegó y 
// cuál es el mensaje.

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Mensaje recibido [");
  Serial.print(topic);
  Serial.print("] ");

  if ((char)payload[0] == 'O') {  // si recibo como primer caracter una O
    if ((char)payload[1] == 'N'){  // si recibo como segundo caracter una N
      Serial.println("El boton esta apagado"); 
      digitalWrite(pin_led, LOW);
    } 
    else {
      Serial.println("El boton esta encendido");  
      digitalWrite(pin_led, HIGH);
    }
  }
}

// Esta función se encarga de conectar con el 
// mqtt broker, si lo consigue se subscribe a
// los tópicos que definamos (no es necesario
// subscribirnos en esta función, pero si lo
// recomiendo para organizar mejor el código.
// Prueba reconectarse cada cinco segundos si
// no lo consigue.

void reconnect() {
  // Loop hasta lograr la conexión
  while (!client.connected()) {
    Serial.print("Intentando conectar al servicio MQTT...");
    
    if (client.connect("ESP8266Client")) {
      Serial.println("Conectado!");
      client.publish("temperatura", "0");    //envío dato
      client.publish("humedad", "0");    //envío dato
    } 
    else 
    {
      Serial.print("Fallo, Resultado=");
      Serial.print(client.state());
      Serial.println("Intetando nuevamente en 5 segundos");
      delay(5000);
    }
  }
}

// En el loop principal no hacemos nada más 
// que verificar si perdimos la conexión con
// el servicio mqtt, que lleguen mensajes y
// actualizamos la temperatura y humedad. 
// El "client.loop();" se encarga de revisar 
// si llegaron mensajes, por lo que habría
// que invocar esta función regularmente.

void loop() {

  if (WiFi.status() != WL_CONNECTED)
  {
    setup_wifi();
  }
  if (!client.connected()) 
  {
    reconnect();
  }
  
  //-------------------------------------------------------
  if ((millis() - tiempo) > 2500)
  {
    tiempo = millis();
    float humedad = dht.readHumidity();
    float temperatura = dht.readTemperature();
    float lux = photocell.getCurrentLux();
    client.publish("estacion/datos", (String(temperatura) + "&&&" + String(humedad) + "&&&" + String(lux)).c_str(),true);
    Serial.print(temperatura);
    Serial.print(" ");
    Serial.print(humedad);
    Serial.print(" ");
    Serial.println(lux);
  }
  //-------------------------------------------------------
}


De esta forma sólo obtenemos los valores sin promediar (lo cual significa que hay muchísimos más datos que de otra forma) por lo que si no disponemos de mucha memoria ram (como es en el caso de la raspberry pi) habría que realizar un promedio cada cierta cantidad de horas, como es el caso de la gráfica de valores históricos.

De esta forma podemos mostrar los valores históricos de los tres sensores (con lo cuál se podrían hacer análisis de las variaciones de temperatura, humedad y luz a lo largo de un año).

A continuación les dejo el código del flujo de la nueva estación meteorológica (sin los valores promedio):

https://mega.nz/#!7kIjGCqB!4Mvq78SucQepGiCdXp9osuNRZIeh3hODLgFcOVFkybk

Acá les dejo el código del flujo de la parte que maneja los valores históricos (con promedio):

https://mega.nz/#!7pRzkQAQ!GKUfib8z-Z7judA3EvsLSXDgjk5Gse-wYoIhKtz5-II

El nuevo código para el micro lo tienen arriba así que no lo subo a mega.