6 minute read

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

Final version

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)

Thingyvers Oled Holder

I build a box + pole in FreeCAD to snap the display-enclosure to:

Box Lid Complete

Intermediate version

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.

Box Lid Complete

Converting these is pretty straight forward with LCDAssistent:

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, 
};