Vamos a montar de una manera sencilla y paso a paso un reloj digital con WeMos. Cogerá la hora en tiempo real via WIFI de un servidor en internet y la mostrara en la pantalla OLED.
Con este proyecto pretendo explicar de manera sencilla como explorar varias posibilidades que tiene WeMos y el ESP8266 que incorpora. Como es conectarse a internet vía WIFI, comunicarse vía puerto serie con el ordenador y mostrar información a través de una pantalla OLED.
Funcionamiento del Reloj
Como ya he comentado vamos a coger la información de internet. Por lo que lo primero que realizara es conectarse por WIFI a internet. Después de conectarse procederá a comprobar cada 10 segundos la fecha y hora de internet y actualizarla. Esta información la enviara tanto por puerto serie como a la pantalla WeMoS. Veremos en ambos casos tanto el proceso de conexión, como la información de fecha y hora actualizada.
Componentes
El montaje es bastante sencillo, necesitamos pocos componentes. Ni siquiera hace falta una protoboard, todo gracias a la facilidad de conexión que tiene WeMos. Los componentes necesarios serian los siguientes:
Se puede usar cualquier WeMos D1 Mini, tanto el pro como el lite.
Librerías para IDE Arduino
Necesitamos ciertas librerías en el IDE de Arduino para el funcionamiento del ESP8266. Para coger la información de la fecha de internet, y para mostrar la información en la pantalla. A continuación tenéis el listado de librerías necesarias y donde conseguirlas.
Las introducimos como cualquier otra librería en Arduino.
Preparación parte electrónica de WeMos
Los WeMos cuando los compras vienen sin soldar los pines de conexión. Vienen varios pines dependiendo de como queramos hacer la conexión. En este caso he decidido soldar los necesarios para poner la pantalla justo encima del ESP8266. Igualmente se puede poner de otras maneras mientras respetemos el patillaje.
Programación del reloj ESP8266
Como he comentado anteriormente vamos a recabar varias posibilidades del WeMos en un único código. Para que resulte más sencillo entenderlo voy a explicar cada proceso por separado. Aunque el código esta pensado para WeMos, se puede usar para hacer un reloj ESP8266 con pequeñas modificaciones con cualquier otra placa que lo incorpore. Al final tenéis todo el código completo para el que quiera pasar directamente a la acción.
Conectarse al WIFI
Primero debemos introducir la información de nuestro wifi para que pueda conectarse. Para ello en las siguientes lineas del código debemos sustituir las xxxx por nuestro ssid y password.
//Configurar wifi const char* ssid = "xxxx"; // añade tu ssid const char* password = "xxxx"; // añade tu password
Después deberemos realizar la conexión al WIFI. Con el siguiente código realizaremos la conexión con los datos introducidos anteriormente, y mandara puntos por puerto serie hasta que se realice la conexión.
WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Tenemos algún otro código semejante introducido para controlar posibles desconexiones, y que en ese caso vuelva a realizar la conexión.
Recoger información de la fecha y hora de internet
A continuación vamos a ver una parte importante del código que necesitamos. Vamos a recoger la información de internet y procesarla posteriormente.
Para ello necesitamos algunos códigos de configuración del cliente y la dirección donde nos vamos a conectar. Además necesitamos indicar la diferencia horaria que tenemos respecto a la hora UTC. No he usado la configuración original para Europa ya que no funcionaba correctamente.
Para que funcionara en otro país correctamente habría que introducir la diferencia horaria donde pone el 60 y el 0. Eso respectivamente son más 60 minutos y horario original. En cambio en el caso de America habría que poner en negativo los minutos que correspondan ya que la diferencia horaria es negativa.
// Definir propiedades NTP #define NTP_OFFSET 60 * 60 // En segundos #define NTP_INTERVAL 60 * 1000 // En milisegundos #define NTP_ADDRESS "pool.ntp.org" // URL NTP // Configura el cliente NTP UDP WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP, NTP_ADDRESS, NTP_OFFSET, NTP_INTERVAL); // Horario Europa Central TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 60}; // Hora de Verano de Europa Central TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 0}; // Hora Estandar de Europa Central Timezone CE(CEST, CET); time_t local, utc;
Posteriormente para recoger la información vamos a comprobar si estamos correctamente conectados al WIFI. Después transformaremos la fecha y hora a nuestro huso horario y lo enviaremos a la funciones correspondientes para enviarlo por puesto serie, y a la pantalla OLED.
Lo que enviamos es la marca de tiempo. Posteriormente la vamos a convertir a una fecha interpretable directamente por un ser humano.
if (WiFi.status() == WL_CONNECTED) //comprobar estado de conexion del WIFI { // Actualizar el cliente NTP y obtener la marca de tiempo UNIX UTC timeClient.update(); unsigned long utc = timeClient.getEpochTime(); //Convertir marca de tiempo UTC UNIX a hora local local = CE.toLocal(utc); // Enviar Fecha y hora por puerto serie printTime(local); // Enviar Fecha y hora a OLED printTimeOLED(local); }
Para finalizar vamos a convertir esa marca de tiempo en texto. Hay varias funciones en el código que lo hacen pero vamos a ver las 2 principales. Por una parte vamos a sacar la fecha y por otra sacaremos la hora. En Ambos casos lo convertimos en un String.
// Funcion para formatear en texto la fecha String convertirTimeATextoFecha(time_t t) { String date = ""; date += days[weekday(t)-1]; date += ", "; date += day(t); date += " "; date += months[month(t)-1]; date += ", "; date += year(t); return date; }
// Funcion para formatear en texto la fecha sin dia de la semana String convertirTimeATextoFechaSinSemana(time_t t) { String date = ""; date += months[month(t)-1]; date += " "; date += year(t); return date; }
Enviar información por puerto serie
Primero debemos configurar a que velocidad se va a realizar la comunicación por puesto serie con el siguiente código.
// Inicializar puerto serie Serial.begin(9600);
Después con la siguiente función enviaremos la información. Con print enviamos cosas en la misma linea y con println hacemos un salto de línea después de enviarlo.
// Funcion para mandar hora por puerto serie void printTime(time_t t) { Serial.println(""); Serial.print("Fecha local: "); Serial.print(convertirTimeATextoFecha(t)); Serial.println(""); Serial.print("Hora local: "); Serial.print(convertirTimeATextoHora(t)); }
Enviar información a pantalla OLED
En este caso es un poco mas complejo que enviarlo por puerto serie pero es semejante.
Primero debemos configurar la pantalla.
// Configurar OLED #define OLED_RESET 0 // GPIO0 Adafruit_SSD1306 display(OLED_RESET);
Seguidamente vamos a inicializarla. Para ello tenemos que seleccionar la dirección que tiene configurada para conectarse por I2C. Normalmente va a tener la 0x3C pero se podría poner también con la 0x3D cambiando un punto de soldadura que viene indicado por la parte trasera de la shield. Finalmente borraremos la información de la pantalla.
// Inicializar OLED display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Inicializa con la direccion I2C 0x3C (para 64x48) display.clearDisplay();
Finalmente para sacar la información por pantalla deberemos usar varios códigos. Vamos a ver como ejemplo la parte en la que enviamos la información de la hora a la pantalla. Usamos varios códigos:
- Primero elegimos el tamaño de las letras con display.setTextSize(1). Con el número seleccionamos el tamaño en lineas de las letras. Esta pantalla tendría un tamaño de 6 lineas.
- Después seleccionamos el color con setTextColor(WHITE).
- A continuación elegimos la posición de escritura setCursor(0,0).
- Luego indicamos que queremos mostrar por pantalla println(«Jorge Sanz»). Comando que funciona igual que en el caso del puerto serie.
- Posteriormente indicamos que mande a la pantalla todo lo anterior display().
- Y para finalizar por seguridad le mandamos clearDisplay().
// Funcion para mostrar hora en pantalla OLED void printTimeOLED(time_t t) { display.setTextSize(1); display.setTextColor(WHITE); display.setCursor(0,0); display.println("Jorge Sanz"); display.println(""); display.setTextSize(2); display.println(convertirTimeATextoHora(t)); display.setTextSize(1); display.print(days[weekday(t)-1]); display.print(" "); display.println(day(t)); display.println(convertirTimeATextoFechaSinSemana(t)); display.display(); display.clearDisplay(); }
Código final
Y para finalizar todo el código completo para ver y descargar.
/***************************************************************************************************** * Reloj wifi con WeMoS (ESP8266) y OLED Shield WeMoS (64x48 pixels) * Reloj digital que coge la hora y fecha internacional de internet cada 10 segundos y la adapta * al horario del pais deseado. * * Autor: Jorge Sanz Sanfructuoso * Web: https://jorgesanz.es/ * ****************************************************************************************************/ //Librerías necesarias #include <ESP8266WiFi.h> #include <WifiUDP.h> #include <NTPClient.h> #include <Time.h> #include <TimeLib.h> #include <Timezone.h> #include <SPI.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> //Configurar wifi const char* ssid = "xxxx"; // añade tu ssid const char* password = "xxxx"; // añade tu password // Definir propiedades NTP #define NTP_OFFSET 60 * 60 // En segundos #define NTP_INTERVAL 60 * 1000 // En milisegundos #define NTP_ADDRESS "pool.ntp.org" // URL NTP // Configura el cliente NTP UDP WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP, NTP_ADDRESS, NTP_OFFSET, NTP_INTERVAL); //Horario Europa Central TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 60}; // Hora de Verano de Europa Central TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 0}; // Hora Estandar de Europa Central Timezone CE(CEST, CET); time_t local, utc; //Configurar Fecha y hora const char * days[] = {"Domingo", "Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado"} ; const char * months[] = {"Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"} ; //Configurar OLED #define OLED_RESET 0 // GPIO0 Adafruit_SSD1306 display(OLED_RESET); void setup() { //Inicializar OLED display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Inicializa con la direccion I2C 0x3C (para 64x48) display.clearDisplay(); display.setTextSize(1); display.setTextColor(WHITE); display.setCursor(0,0); display.println("jorgesanz.es"); display.setTextSize(2); display.println("RELOJ"); display.setTextSize(1); display.display(); //Inicializar puerto serie Serial.begin(9600); // Conectar a wifi // // Puerto serie Serial.println(""); Serial.print("conectando a "); Serial.print(ssid); // Pantalla OLED display.println("conectando"); display.print(ssid); display.display(); display.clearDisplay(); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.print("Conectando WiFi a "); Serial.print(WiFi.localIP()); Serial.println(""); } void loop() { if (WiFi.status() == WL_CONNECTED) //comprobar estado de conexion del WIFI { // Actualizar el cliente NTP y obtener la marca de tiempo UNIX UTC timeClient.update(); unsigned long utc = timeClient.getEpochTime(); //Convertir marca de tiempo UTC UNIX a hora local local = CE.toLocal(utc); // Enviar Fecha y hora por puerto serie printTime(local); // Enviar Fecha y hora a OLED printTimeOLED(local); } else // Intenta conectarse a wifi de nuevo si está desconectado { WiFi.begin(ssid, password); delay(1000); } delay(10000); // Enviar una solicitud para actualizar cada 10 seg (= 10,000 ms) } //Funcion para formatear en texto la fecha String convertirTimeATextoFecha(time_t t) { String date = ""; date += days[weekday(t)-1]; date += ", "; date += day(t); date += " "; date += months[month(t)-1]; date += ", "; date += year(t); return date; } //Funcion para formatear en texto la fecha sin dia de la semana String convertirTimeATextoFechaSinSemana(time_t t) { String date = ""; date += months[month(t)-1]; date += " "; date += year(t); return date; } //Funcion para formatear en texto la hora String convertirTimeATextoHora(time_t t) { // Formatear la hora sin segundos String hora =""; if(hour(t) < 10) hora += "0"; hora += hour(t); hora += ":"; if(minute(t) < 10) // Agregar un cero si el minuto es menor de 10 hora += "0"; hora += minute(t); return hora; } //Funcion para mandar hora por puerto serie void printTime(time_t t) { Serial.println(""); Serial.print("Fecha local: "); Serial.print(convertirTimeATextoFecha(t)); Serial.println(""); Serial.print("Hora local: "); Serial.print(convertirTimeATextoHora(t)); } //Funcion para mostrar hora en pantalla OLED void printTimeOLED(time_t t) { display.setTextSize(1); display.setTextColor(WHITE); display.setCursor(0,0); display.println("Jorge Sanz"); display.println(""); display.setTextSize(2); display.println(convertirTimeATextoHora(t)); display.setTextSize(1); display.print(days[weekday(t)-1]); display.print(" "); display.println(day(t)); display.println(convertirTimeATextoFechaSinSemana(t)); display.display(); display.clearDisplay(); }
Montaje y resultado final de funcionamiento del Reloj WeMos con pantalla OLED
Con esto ya tenemos en funcionamiento nuestro reloj. Aquí tenéis como quedaría.