In the wake of becoming a parent, I need to nerd some stuff together for the unborn, and to have an excuse to use my 3dprinter and soldering iron and hack togehter some quick-n-dirty code:)
So I cobbled a small thermometer together using
- a small microcontroller
- a graphical display
- a temperature sensor (as the DTH11’s is rather imprecise)
- a humidity sensor
Components
- Arduino (pro micro board) (uC)
- SD1306 (I2C graphic LCD)
- Dallas DS1206 (Temperature sensor)
- DTH11 (Humidity)
Software
- Arduino
- LCDAssistent
- Ifranview to do the icon-editing
3d models
As I found this great Thing (https://www.thingiverse.com/thing:1414793)
I build a box + pole in FreeCAD to snap the display-enclosure to:
Code
As I liked to have some icons, i made some:
Just a note to self, the Adafruits Gfx library (or LCDAssistent) seems to ‘dislike’ bitmaps with height/widh different from 2^8’s, so 32 x … works, 33 will give garbage.
Converting these is pretty straight forward with LCDAssistent:
Now we only need to save the output, and change the variable declaration to include the keyword PROGMEM:
const unsigned char PROGMEM termo_32x49 [] = {
...
}
baby-monitor.INO
//Author: Vincent Gijsen
//date: 29-04-29
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <avr/wdt.h>
#include "DHT.h"
#define DHTPIN 10 // what digital pin we're connected to
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
float globalHumid = 0;
float globalTemp = 0;
float globalHeatIndex = 0;
#include <OneWire.h>
#include <DallasTemperature.h>
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);
#define ONE_WIRE_BUS 13
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress insideThermometer;
#include "icons.hpp"
#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif
//prototypes
void generateBanner(void);
void setup() {
sensors.begin();
dht.begin();
if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0");
sensors.requestTemperatures();
display.begin(SSD1306_SWITCHCAPVCC, 0x3c); // initialize with the I2C addr 0x3D (for the 128x64)
display.clearDisplay();
generateBanner();
}
void clearLowerSection() {
#define CLSTARTX 0
#define CLSTARTY 17
#define CLLENX ((128) - (CLSTARTX))
#define CLLENY ((64) - (CLSTARTY))
display.fillRect(CLSTARTX, CLSTARTY, CLLENX, CLLENY, BLACK); //fill background
}
void generateBanner() {
display.fillRect(0, 0, 128, 16, WHITE); //fill background
display.setTextColor(BLACK); // write intverted text
display.setTextSize(1);
display.setCursor(30, 5);
display.print("Baby Monitor");
}
void showHeatIndex() {
#define HEAT_X 0
#define HEAT_Y 16
#define HEAT_W 32
#define HEAT_H 45
#define HEATOFFSET 10
clearLowerSection();
display.drawBitmap(HEAT_X, HEAT_Y, heatindex_32x53, HEAT_W, HEAT_H, WHITE);
display.setCursor(HEAT_X + HEAT_W + HEATOFFSET, HEAT_Y + (HEAT_H / 4) );
display.setTextSize(2);
display.setTextColor(WHITE);
if (globalHeatIndex == 0) {
display.print("ERROR");
} else {
//calculated in Humidity Section
display.print(globalHeatIndex);
display.print(" ");
}
display.display();
}
void showHumid() {
#define HUM_X 0
#define HUM_Y 16
#define HUM_W 32
#define HUM_H 45
#define HUMOFFSET 10
clearLowerSection();
display.drawBitmap(HUM_X, HUM_Y, humid_32x45, HUM_W, HUM_H, WHITE);
display.setCursor(HUM_X + HUM_W + HUMOFFSET, HUM_Y + (HUM_H / 4) );
display.setTextSize(2);
display.setTextColor(WHITE);
if (isnan(globalHumid)) {
globalHeatIndex = 0;
display.print("ERROR");
} else {
globalHeatIndex = dht.computeHeatIndex(globalTemp, globalHumid, false);
display.print(globalHumid);
display.print(" %");
}
display.display();
}
void showTemp(DeviceAddress deviceAddress) {
sensors.requestTemperatures();
#define LOGO_X 0
#define LOGO_Y 16
#define LOGO_W 32
#define LOGO_H 49
#define OFFSET 10
clearLowerSection();
display.drawBitmap(LOGO_X, LOGO_Y, termo_32x49, LOGO_W, LOGO_H, WHITE);
display.setCursor(LOGO_X + LOGO_W + OFFSET, LOGO_Y + (LOGO_H / 4) );
display.setTextSize(2);
display.setTextColor(WHITE);
float tempC = sensors.getTempC(deviceAddress);
globalTemp = tempC;
display.print(globalTemp);
display.print(" C");
display.display();
}
void loop() {
wdt_enable(WDTO_8S);
showTemp(insideThermometer);
delay(1000);
globalHumid = dht.readHumidity();
showHumid();
delay(1000);
showHeatIndex();
delay(1000);
}
the icons.hpp
const unsigned char PROGMEM termo_32x49 [] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x00, 0xE1, 0xC0, 0x00,
0x00, 0xC0, 0xC0, 0x00, 0x01, 0x80, 0xC1, 0xFC, 0x01, 0x80, 0xC3, 0xFC, 0x01, 0x80, 0xC0, 0x00,
0x01, 0x80, 0xC0, 0x00, 0x01, 0x80, 0xC0, 0x00, 0x01, 0x80, 0xC0, 0x00, 0x01, 0x80, 0xC1, 0xFC,
0x01, 0x80, 0xC3, 0xFC, 0x01, 0x80, 0xC0, 0x00, 0x01, 0x80, 0xC0, 0x00, 0x01, 0x80, 0xC0, 0x00,
0x01, 0x80, 0xC0, 0x00, 0x01, 0x8C, 0xC1, 0xFC, 0x01, 0x8C, 0xC3, 0xFC, 0x01, 0x8C, 0xC0, 0x00,
0x01, 0x8C, 0xC0, 0x00, 0x01, 0x8C, 0xC0, 0x00, 0x01, 0x8C, 0xC0, 0x00, 0x01, 0x8C, 0xC0, 0xFC,
0x01, 0x8C, 0xC0, 0xFC, 0x01, 0x8C, 0xC0, 0x00, 0x01, 0x8C, 0xE0, 0x00, 0x07, 0x8C, 0x70, 0x00,
0x0E, 0x0C, 0x38, 0x00, 0x1C, 0x1E, 0x0C, 0x00, 0x18, 0x7F, 0x8E, 0x00, 0x38, 0xFF, 0xC6, 0x00,
0x31, 0xFF, 0xE3, 0x00, 0x33, 0xFF, 0xE3, 0x00, 0x73, 0xFF, 0xF3, 0x00, 0x63, 0xFF, 0xF3, 0x00,
0x63, 0xFF, 0xF3, 0x00, 0x63, 0xFF, 0xF3, 0x00, 0x73, 0xFF, 0xF3, 0x00, 0x31, 0xFF, 0xE3, 0x00,
0x31, 0xFF, 0xE7, 0x00, 0x18, 0xFF, 0xC6, 0x00, 0x1C, 0x3F, 0x0E, 0x00, 0x0E, 0x00, 0x1C, 0x00,
0x07, 0x00, 0x38, 0x00, 0x03, 0xE1, 0xF0, 0x00, 0x01, 0xFF, 0xC0, 0x00, 0x00, 0x3F, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
const unsigned char PROGMEM humid_32x45 [] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xE0,
0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x03, 0xFC,
0x00, 0x00, 0x03, 0xFC, 0x00, 0x02, 0x03, 0xFC, 0x00, 0x07, 0x03, 0xFC, 0x00, 0x0F, 0x03, 0xFC,
0x00, 0x1F, 0x83, 0xFC, 0x00, 0x1F, 0xC1, 0xF8, 0x00, 0x1F, 0xE0, 0xF0, 0x00, 0x3F, 0xE0, 0x00,
0x00, 0x7F, 0xF0, 0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xF8, 0x00,
0x01, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFC, 0x00, 0x03, 0x1F, 0x8E, 0x00, 0x04, 0x07, 0x0E, 0x00,
0x04, 0x03, 0x0F, 0x00, 0x00, 0x42, 0x1F, 0x00, 0x08, 0x40, 0x3F, 0x00, 0x08, 0x40, 0x3F, 0x80,
0x08, 0x40, 0x07, 0x80, 0x0C, 0x00, 0x03, 0x80, 0x0C, 0x00, 0x01, 0x80, 0x0E, 0x00, 0x11, 0x80,
0x0F, 0x00, 0x31, 0x00, 0x0F, 0xE2, 0x31, 0x00, 0x0F, 0xE2, 0x31, 0x00, 0x07, 0xC2, 0x11, 0x00,
0x07, 0xC6, 0x00, 0x00, 0x03, 0x8E, 0x02, 0x00, 0x03, 0x8F, 0x00, 0x00, 0x01, 0x9F, 0xCC, 0x00,
0x00, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00, 0x06, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
const unsigned char PROGMEM heatindex_32x53 [] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x01, 0x80, 0xE0, 0x03, 0x81, 0xC0, 0xE0, 0x07, 0x03, 0xC1, 0xE0, 0x07, 0x03, 0x81, 0xE0,
0x0F, 0x07, 0x81, 0xC0, 0x0E, 0x07, 0x83, 0xC0, 0x0E, 0x07, 0x03, 0xC0, 0x1E, 0x07, 0x03, 0x80,
0x1C, 0x07, 0x03, 0x80, 0x1C, 0x0E, 0x03, 0x80, 0x1C, 0x0E, 0x03, 0x80, 0x1C, 0x0E, 0x07, 0x80,
0x3C, 0x0E, 0x07, 0x80, 0x3C, 0x0E, 0x07, 0x80, 0x3C, 0x0E, 0x07, 0x80, 0x1C, 0x0F, 0x07, 0x80,
0x1E, 0x0F, 0x03, 0x80, 0x1E, 0x07, 0x83, 0xC0, 0x0F, 0x07, 0x83, 0xC0, 0x07, 0x03, 0xC1, 0xE0,
0x07, 0x81, 0xE0, 0xF0, 0x03, 0xC1, 0xE0, 0xF8, 0x03, 0xC0, 0xF0, 0x78, 0x01, 0xE0, 0x70, 0x78,
0x00, 0xE0, 0x78, 0x3C, 0x00, 0xE0, 0x78, 0x3C, 0x00, 0xE0, 0x38, 0x1C, 0x00, 0xE0, 0x38, 0x1C,
0x00, 0xE0, 0x38, 0x1C, 0x00, 0xE0, 0x38, 0x1C, 0x00, 0xE0, 0x78, 0x3C, 0x00, 0xE0, 0x78, 0x38,
0x00, 0xE0, 0x70, 0x78, 0x01, 0xE0, 0xF0, 0x78, 0x01, 0xC0, 0xE0, 0xF0, 0x03, 0xC1, 0xE0, 0xF0,
0x03, 0x81, 0xC1, 0xE0, 0x07, 0x83, 0xC1, 0xC0, 0x07, 0x03, 0x81, 0xC0, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00,
};
Twitter
Google+
Facebook
Reddit
LinkedIn
StumbleUpon
Pinterest
Email