Medidor de temperatura casero

Dado que tengo unos cuantos arduino pro micro que he usado para otras cosas, creí bastante conveniente diseñarle una placa para poder ponerle un display oled de 0,96 pulgadas (ssd1306 que ya utilicé en otras entradas) para poder hacer proyectos rápido (en principio pensando en conectarlo a un ordenador y que actúe como teclado, ratón y/o puerto serie). El esquema es el siguiente:

Y la placa resultante quedó así:

Podéis encontrar el proyecto, por si queréis mejorarlo en https://easyeda.com/biblioeteca/promicro-oled

El caso es que, lo primero que se me ocurrió para probarlo, una vez recibidas las placas, fue utilizar otro componente que tenía desde hace tiempo (un sensor de temperatura) y convertirlo en un termómetro… Una pena que no pensara en ello al hacer la placa, por lo que tendré que hacer alguna soldadura de más para conectar el sensor. En concreto quedaría así:

Que visto después de aplicar el soldador se vería así (he aprovechado las pistas de GND y VCC que llegaban al display):

Visto por el otro lado:

La parte de programar la temperatura es un poco más «liosa», básicamente habría que leer la hoja de especificaciones del termistor y resolver la ecuación de Steinhart-hart.

En mi caso, con el valor de 10KOhm en la resistencia y el modelo de termistor que tenía (aquí su hoja de especificaciones) el código resultante para leer la temperatura quedó así:

const int Rc = 10000; //valor de la resistencia
const int Vcc = 5;
const int SensorPIN = A0;
 
float A = 1.11492089e-3;
float B = 2.372075385e-4;
float C = 6.954079529e-8;
 
float K = 2.5; //factor de disipacion en mW/C

void loop() {
  float raw = analogRead(SensorPIN);
  float V =  raw / 1024 * Vcc;
  float R = (Rc * V ) / (Vcc - V);
  float logR  = log(R);
  float R_th = 1.0 / (A + B * logR + C * logR * logR * logR );
  float kelvin = R_th - V*V/(K * R)*1000;
  float celsius = kelvin - 273.15;
  delay(2000);
  // Imprimir la temperatura...
}

Para sacar en el display la temperatura he utilizado la librería Adafruit_SSD1306 que depende de Adafruit_GFX y permite hacer bastantes cosas… Eso sí, dado que mi arduino era lento (estoy usando el de 3.3v) he tenido que inicializar el display cambiando la velocidad del I2C a 400Mhz para que no se note demasiado lag (este display hay que limpiar la zona en la que escribes antes y eso quita ciclos).

Finalmente, una vez probado que funciona, mi intención es hacerlo portable, por lo que le he añadido una pila de 6v conectada a los pines «raw» y «gnd» (el pro micro tiene una entrada regulada en el pin raw) y le he montado una carcasa… Quedando de esta manera (si queréis más detalles me los pedís):

Probando cosillas con arduino beetle

Lo que veis en la foto es un arduino beeetle, bueno, realmente es una placa pro micro con menos pines de los que debería y un conector directo a usb… Como véis es muy pequeño y podéis encontrarlo por un precio bastante económico, aquí, por ejemplo.

Yo ya había utilizado antes el arduino pro micro (leonardo compatible) para simular un teclado en otro proyecto, por lo que sabía que podría utilizar este también para algo similar. Dado su tamaño y lo fácil que se camufla como un «pincho» usb podría pasar desapercibido a la vista… Así que me decidí a ir un pasito más y añadirle un poco más de hardware para controlarlo. Qué mejor que ponerle un botón para indicarle cuando quiero que «teclee algo»… Para ello me aprovecho de que los pines digitales pueden actuar como pull-up y solo tenía que conectar el interruptor entre un pin digital y tierra. En mi caso lo conecté entre el D9 y GND como se puede ver en la foto:

Hice las soldaduras por detrás para proteger un poco más los componentes, pero podría ponerse por delante teniendo un poco más de cuidado.

Una vez el hardware preparado llega el momento de hacer las cosas interesantes… Tampoco es que vaya a ser muy original, pero aquí os dejo el programa que cargué inicialmente…. Funciona en windows y lo que consigues cuando pulsas el botón es que se te abra el chrome con la página web nomorepass.com… (igual sirve como propaganda y todo).

#include "Keyboard.h"
const int buttonPin = 9;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  Keyboard.begin();
}

void loop() {
  while (digitalRead(buttonPin) == HIGH) {
    delay(200);
  }
  delay(100);
  Keyboard.press(KEY_LEFT_GUI);
  Keyboard.press('r');
  Keyboard.releaseAll();
  delay(500);
  Keyboard.print("chrome https>&&nomorepass.com");
  Keyboard.write(KEY_RETURN);
  delay(500);
}

Básicamente lo único que hace es esperar a que el estado del pin al que está conectado el botón pase de alto a bajo (esto es así por la configuración INPUT_PULLUP) y cuando cambia, señal de que hemos pulsado el botón, lo que hace es enviar un COMMAND+r que abre el diálogo de ejecutar de windows y luego envía el texto chrome https://nomorepass.com. Como se puede ver he tenido que transliterar los caracteres que en el teclado americano están colocados en otro sitio (un defectillo de la librería de arduino).

Visto que funciona… Pues ya solo queda hacer una cajita e imprimirla en 3d:

He dejado el diseño en thingiverse por lo que podéis aprovecharlo… Mientras, a inventarnos cosas que hacer con el trasto… «No demasiado diabólicas»..

Construyendo un dispositivo inteligente con nodemcu y un display OLED

Últimamente se están poniendo de moda los dispositivos «inteligentes» que, básicamente, consiste en cacharros que están conectados de una manera o de otra a internet o a nuestra red doméstica y que aceptan comandos desde la red para controlar sus distintas funciones.

La verdad es que han bajado mucho de precio y el poder controlarlas desde los distintos asistentes de voz le dan un extra adicional. He trasteado un poco con Alexa y con Google Home, pero todavía estoy en el proceso de encontrarle el sitio correcto. En cualqueir caso, como soy un alma inquieta he preferido ver cuanto me costaba crear mi propio «dispositivo inteligente» con los materiales que tenía a mano… Esto es lo que he usado:

  • Pantalla OLED de 1,3″ con el chip SSH1106 de 128×64. En concreto esta.
  • Una placa Weimos D1 mini (compatible), que se basa en el chip ESP8266. En concreto esta.
  • Un relé preparado para 5V. En mi caso este.

El chip ESP8266 es una maravilla que integra wifi junto con un microcontrolador que puede ser programado desde el IDE del Arduino (entre otras formas) y el empaquetado en forma de placa nocemcu hace que sea muy sencillo hacer proyectos con este, siendo más barato y más potente que un arduino habitual. De hecho los componentes de este proyecto comprados en aliexpress (quitando cables y gastos de envío) no suman más de 6 Euros… Irresistible para montar un prototipo.

Al lío… Es esquema de conexiones es este:

En realidad el pulsador no hace falta, lo he incluido para poder comunicar al dispositivo manualmente el cambio de estado (es un rollo tener que hacerlo todo en remoto) y no es necesario para la primera versión.

Para poder programar la placa desde el IDE del Arduino vamos a tener que ir a la sección de Archivo->Preferencias y añadir la url http://arduino.esp8266.com/stable/package_esp8266com_index.json en el campo Gestor de URLs Adicionales de Tarjetas, quedando como en la imagen:

Luego nos vamos a Herramientas->Placas->Gestión de tarjetas y buscamos ESP8266 e instalamos la versión de ESP8266 Community.

Con esto ya nos aparecerá el tipo de tarjeta Wemos o NodeMCU en la lista de tarjetas que podemos conectar con el IDE.

Lo siguiente es encontrar una librería que nos permita interactuar por I2C con nuestra pantalla (y que sea lo más flexible posible para usos futuros). Esto es lo que me llevó más tiempo, básicamente porque los ejemplos que proporcionan están preparados para otro chip y la nomenclatura de los pines es diferente… Al final la mejor es esta:

https://github.com/ThingPulse/esp8266-oled-ssd1306

Yo he usado como base el ejemplo que viene al instalar la placa y se llama WIFIServer (creo que lo han cambiado por una versión nueva, os dejo el código completo al final de todas formas). El funcionamiento es de tal manera que al arrancar se conecta a la red wifi que tengamos configurada y queda esperando conexiones, cuando recibe una petición https://server_ip/gpio/0 ponemos a cero el GPIO2 y si recibimos una https://server_ip/gpio/1 lo ponemos a 1… Como esa salida la tenemos conectada al relé, pues ya podemos encender o apagar lo que queramos desde la web.

Para sacar la información por la pantalla, básicamente, utilizo la función drawString que me imprime en las coordenadas dadas de la pantalla una cadena (y en la fuente que hayamos seleccionado antes)… Podéis verlo en funcionamiento en este video:

Os pongo el código antes de integrar lo del botón… Básicamente lo que falta por poner es que cuando detectemos una pulsación del botón (D3 pase a cero) cambiemos el estado del pin conectado al relé (así tenemos control manual, cosa que echo de menos en las bombillas inteligentes, por ejemplo).


#include <ESP8266WiFi.h>
#include "SH1106Wire.h"

const char* ssid = "tussid";
const char* password = "tupassword";

SH1106Wire display(0x3c, 4, 5);

WiFiServer server(80);

void setup() {
 
  Serial.begin(115200);
  delay(10);

  pinMode(2, OUTPUT);
  digitalWrite(2, 0);
  
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  display.init();
  display.flipScreenVertically();
  display.setFont(ArialMT_Plain_10);

  display.clear();
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.drawString(0,0,"Connecting...");
  display.display();
      
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  
  display.clear();
  display.drawString(0,0,String(ssid));
  display.drawString(0,10, "IP: "+WiFi.localIP().toString());
  display.display();
    
  // Start the server
  server.begin();
  Serial.println("Server started");

  // Print the IP address
  Serial.println(WiFi.localIP());
}

void loop() {
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
  
  Serial.println("new client");
  while(!client.available()){
    delay(1);
  }
  
  String req = client.readStringUntil('\r');
  Serial.println(req);
  client.flush();
  
  int val;
  if (req.indexOf("/gpio/0") != -1)
    val = 0;
  else if (req.indexOf("/gpio/1") != -1)
    val = 1;
  else {
    Serial.println("invalid request");
    client.stop();
    return;
  }

  digitalWrite(2, val);
  display.setColor(BLACK);
  display.fillRect(0, 26, 100, 10);
  display.setColor(WHITE);
  display.drawString(0,26,"GPIO: "+String(val));
  display.display();
  
  client.flush();

  String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nGPIO is now ";
  s += (val)?"high":"low";
  s += "</html>\n";

  client.print(s);
  delay(1);
  Serial.println("Client disonnected");
}

Si habéis leido el código veréis que hay algunas cosas que se hacen de más, por ejemplo, pintamos un rectángulo en negro para borrar la línea antes de pintarla de nuevo con el valor del GPIO. Eso es debido a que esta librería está pensada para borrar la pantalla cada vez que la actualicemos y, por eso, no limpia el hueco en el que va a escribir (igual podemos hacer un fork que lo solucione, ya veremos) y sin esa limpieza las letras se escriben unas encima de otras.

Una nota final… El servidor no envía cabeceras CORS, por lo que si vais a utilizarlo desde javascript en cualquier otro servidor os saltará un error en la consola (y en mac ni siquiera hará la llamada real), en linux y windows funcionará aunque no recibiréis la respuesta.

Sigo modificando el código y demás a ver qué termino consiguiendo… Hasta es posible que le diseñe un PCB… Ya os iré contando.