ESP8266/DHT
< ESP8266
Humidity/Temperature sensor with SD Card data logger.
This code is for use with NUBCore #060 hardware and a DHT11 sensor.
The DHT11 sensor seems to return eroneous data when sampled quickly, here it seems to be stable at once a minute.
Note: Requires modified Nokia library (see below).
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <SPI.h>
#include <SD.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <DHT.h>
#define DHTTYPE DHT11
#define PIN_DHT 1
#define PIN_CE 16 //Pin 2 on LCD
#define PIN_DC 15 //Pin 3 on LCD
#define PIN_SD_CS 10 // Make sure "DIO" is selected
#define DISPLAY_ENABLED true
bool sdEnabled = false;
WiFiClient client;
#if defined(DISPLAY_ENABLED)
Adafruit_PCD8544 display = Adafruit_PCD8544(PIN_DC, PIN_CE, -1);
#else
Adafruit_PCD8544 display = Adafruit_PCD8544(4, 5, 2, -1);
#endif
bool wifiEnabled = false;
DHT dht(PIN_DHT, DHTTYPE);
void handleHumidity(void);
void setup() {
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
if (DISPLAY_ENABLED) {
display.begin();
display.setContrast(55);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(0, 0);
display.println("#0FF DHT");
display.setTextColor(WHITE, BLACK); // 'inverted' text
display.setTextSize(2);
display.println(" void ");
display.setTextSize(1);
display.setTextColor(BLACK);
display.display();
}
WiFi.begin(); // Usese last configured settings
// WiFi.begin("ssid", "password");
unsigned long timeout = millis() + 10000;
while (WiFi.status() != WL_CONNECTED) {
digitalWrite(5, HIGH);
delay(50);
digitalWrite(5, LOW);
delay(450);
yield();
if (millis() > timeout)
break;
}
wifiEnabled = WiFi.status() == WL_CONNECTED;
if (wifiEnabled) {
ArduinoOTA.onStart([]() {
if (DISPLAY_ENABLED) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(0, 0);
display.println("*OTA Update*");
display.println("");
display.setTextSize(2);
display.display();
}
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
static uint8_t lastProgress = 0;
static unsigned long nextTime = 0;
uint8_t p = (progress / (total / 100));
if (p == 100 || (p != lastProgress && millis() > nextTime)) {
nextTime = millis() + 100;
if (p < 100) {
if (DISPLAY_ENABLED) {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
display.println("*OTA Update*");
display.println("");
display.setTextSize(2);
display.setCursor(24, 24);
display.println(String(p) + "%");
display.display();
}
lastProgress = p;
} else {
if (DISPLAY_ENABLED) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(0, 0);
display.println("*OTA Success*");
display.println("");
display.println("rebooting...");
display.display();
}
}
}
});
ArduinoOTA.onError([](ota_error_t error) {
if (DISPLAY_ENABLED) {
display.println("ERROR: " + String(error));
display.display();
delay(1000);
}
});
ArduinoOTA.begin();
if (DISPLAY_ENABLED) {
display.println(WiFi.SSID());
display.println(WiFi.localIP());
display.display();
}
for (int i = 0; i < 10; i++) {
ArduinoOTA.handle();
delay(100);
yield();
}
}
if (!SD.begin(PIN_SD_CS)) {
// no SD found
display.clearDisplay();
display.println("No SD found");
display.display();
// TODO: change delay to loop w/yield
delay(1000);
yield();
} else {
// SD initialized
sdEnabled = true;
}
dht.begin();
delay(100);
}
void loop() {
if (wifiEnabled)
ArduinoOTA.handle();
handleHumidity();
delay(50);
}
void handleHumidity() {
static unsigned long next = 10000; // Don't read for first 10 seconds
unsigned long now = millis();
if (now > next) {
bool validData = false;
next = now + 60000; // Read every 60 seconds
// Blip LED
digitalWrite(5, HIGH);
float h, c, f;
h = dht.readHumidity();
c = dht.readTemperature();
f = dht.readTemperature(true);
validData = (h >= 0 && h <= 100);
if (validData) {
display.clearDisplay();
display.setCursor(0, 0);
display.setTextSize(2);
display.println(String(int(c)) + "/" + String(int(f)));
display.setTextSize(3);
display.println(String(int(h)) + "%");
display.display();
if (sdEnabled) {
String data = String(millis()) + ",";
data += String(h) + ",";
data += String(c) + ",";
data += String(f);
File dataFile = SD.open("HUMIDITY.TXT", FILE_WRITE);
if (dataFile) {
dataFile.println(data);
dataFile.close();
}
}
} else {
display.println("DATA ERROR");
display.display();
}
digitalWrite(5, LOW);
}
}
Slightly modified version of Adafruit Nokia Display library (Adafruit_PCD8544.cpp)...
/*********************************************************************
This is a library for our Monochrome Nokia 5110 LCD Displays
Pick one up today in the adafruit shop!
------> http://www.adafruit.com/products/338
These displays use SPI to communicate, 4 or 5 pins are required to
interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, check license.txt for more information
All text above, and the splash screen below must be included in any redistribution
Hacked for ESP8266 by thex #0ff
*********************************************************************/
//#include <Wire.h>
#if defined(ESP8266)
#include <pgmspace.h>
#else
#include <avr/pgmspace.h>
#endif
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#ifdef __AVR__
#include <util/delay.h>
#endif
#ifndef _BV
#define _BV(x) (1 << (x))
#endif
#include <stdlib.h>
#include <Adafruit_GFX.h>
#include "Adafruit_PCD8544.h"
// the memory buffer for the LCD
uint8_t pcd8544_buffer[LCDWIDTH * LCDHEIGHT / 8] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFC, 0xFE, 0xFF, 0xFC, 0xE0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
0xF8, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x80, 0xC0, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x7F,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC7, 0xC7, 0x87, 0x8F, 0x9F, 0x9F, 0xFF, 0xFF, 0xFF,
0xC1, 0xC0, 0xE0, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFC, 0xFC, 0xFC, 0xFE, 0xFE, 0xFE,
0xFC, 0xFC, 0xF8, 0xF8, 0xF0, 0xE0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x80, 0xC0, 0xE0, 0xF1, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0x0F, 0x0F, 0x87,
0xE7, 0xFF, 0xFF, 0xFF, 0x1F, 0x1F, 0x3F, 0xF9, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xFD, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x0F, 0x07, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xF0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
0x7E, 0x3F, 0x3F, 0x0F, 0x1F, 0xFF, 0xFF, 0xFF, 0xFC, 0xF0, 0xE0, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFC, 0xF0, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01,
0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x1F, 0x3F, 0x7F, 0x7F,
0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x1F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
// reduces how much is refreshed, which speeds it up!
// originally derived from Steve Evans/JCW's mod but cleaned up and
// optimized
//#define enablePartialUpdate
#ifdef enablePartialUpdate
static uint8_t xUpdateMin, xUpdateMax, yUpdateMin, yUpdateMax;
#endif
static void updateBoundingBox(uint8_t xmin, uint8_t ymin, uint8_t xmax, uint8_t ymax) {
#ifdef enablePartialUpdate
if (xmin < xUpdateMin) xUpdateMin = xmin;
if (xmax > xUpdateMax) xUpdateMax = xmax;
if (ymin < yUpdateMin) yUpdateMin = ymin;
if (ymax > yUpdateMax) yUpdateMax = ymax;
#endif
}
Adafruit_PCD8544::Adafruit_PCD8544(int8_t SCLK, int8_t DIN, int8_t DC,
int8_t CS, int8_t RST) : Adafruit_GFX(LCDWIDTH, LCDHEIGHT) {
_din = DIN;
_sclk = SCLK;
_dc = DC;
_rst = RST;
_cs = CS;
}
Adafruit_PCD8544::Adafruit_PCD8544(int8_t SCLK, int8_t DIN, int8_t DC,
int8_t RST) : Adafruit_GFX(LCDWIDTH, LCDHEIGHT) {
_din = DIN;
_sclk = SCLK;
_dc = DC;
_rst = RST;
_cs = -1;
}
Adafruit_PCD8544::Adafruit_PCD8544(int8_t DC, int8_t CS, int8_t RST):
Adafruit_GFX(LCDWIDTH, LCDHEIGHT) {
// -1 for din and sclk specify using hardware SPI
_din = -1;
_sclk = -1;
_dc = DC;
_rst = RST;
_cs = CS;
}
// the most basic function, set a single pixel
void Adafruit_PCD8544::drawPixel(int16_t x, int16_t y, uint16_t color) {
if ((x < 0) || (x >= _width) || (y < 0) || (y >= _height))
return;
int16_t t;
switch(rotation){
case 1:
t = x;
x = y;
y = LCDHEIGHT - 1 - t;
break;
case 2:
x = LCDWIDTH - 1 - x;
y = LCDHEIGHT - 1 - y;
break;
case 3:
t = x;
x = LCDWIDTH - 1 - y;
y = t;
break;
}
if ((x < 0) || (x >= LCDWIDTH) || (y < 0) || (y >= LCDHEIGHT))
return;
// x is which column
if (color)
pcd8544_buffer[x+ (y/8)*LCDWIDTH] |= _BV(y%8);
else
pcd8544_buffer[x+ (y/8)*LCDWIDTH] &= ~_BV(y%8);
updateBoundingBox(x,y,x,y);
}
// the most basic function, get a single pixel
uint8_t Adafruit_PCD8544::getPixel(int8_t x, int8_t y) {
if ((x < 0) || (x >= LCDWIDTH) || (y < 0) || (y >= LCDHEIGHT))
return 0;
return (pcd8544_buffer[x+ (y/8)*LCDWIDTH] >> (y%8)) & 0x1;
}
void Adafruit_PCD8544::begin(uint8_t contrast, uint8_t bias) {
if (isHardwareSPI()) {
// Setup hardware SPI.
SPI.begin();
#ifdef ESP8266
// Datasheet says 4 MHz is max SPI clock speed
SPI.setFrequency(400000);
#else
SPI.setClockDivider(PCD8544_SPI_CLOCK_DIV);
#endif
SPI.setDataMode(SPI_MODE0);
SPI.setBitOrder(MSBFIRST);
}
else {
// Setup software SPI.
// Set software SPI specific pin outputs.
pinMode(_din, OUTPUT);
pinMode(_sclk, OUTPUT);
#ifndef ESP8266
// Set software SPI ports and masks.
clkport = portOutputRegister(digitalPinToPort(_sclk));
clkpinmask = digitalPinToBitMask(_sclk);
mosiport = portOutputRegister(digitalPinToPort(_din));
mosipinmask = digitalPinToBitMask(_din);
#endif
}
// Set common pin outputs.
pinMode(_dc, OUTPUT);
if (_rst > 0)
pinMode(_rst, OUTPUT);
if (_cs > 0)
pinMode(_cs, OUTPUT);
// toggle RST low to reset
if (_rst > 0) {
digitalWrite(_rst, LOW);
delay(500);
digitalWrite(_rst, HIGH);
}
// get into the EXTENDED mode!
command(PCD8544_FUNCTIONSET | PCD8544_EXTENDEDINSTRUCTION );
// LCD bias select (4 is optimal?)
command(PCD8544_SETBIAS | bias);
// set VOP
if (contrast > 0x7f)
contrast = 0x7f;
command( PCD8544_SETVOP | contrast); // Experimentally determined
// normal mode
command(PCD8544_FUNCTIONSET);
// Set display to Normal
command(PCD8544_DISPLAYCONTROL | PCD8544_DISPLAYNORMAL);
// initial display line
// set page address
// set column address
// write display data
// set up a bounding box for screen updates
updateBoundingBox(0, 0, LCDWIDTH-1, LCDHEIGHT-1);
// Push out pcd8544_buffer to the Display (will show the AFI logo)
display();
}
inline void Adafruit_PCD8544::spiWrite(uint8_t d) {
if (isHardwareSPI()) {
// Hardware SPI write.
SPI.transfer(d);
}
else {
#ifdef ESP8266
// Software SPI write with bit banging.
for(uint8_t bit = 0x80; bit; bit >>= 1) {
digitalWrite(_sclk, LOW);
if (d & bit) digitalWrite(_din, HIGH);
else digitalWrite(_din, LOW);
digitalWrite(_sclk, HIGH);
}
#else
// Software SPI write with bit banging.
for(uint8_t bit = 0x80; bit; bit >>= 1) {
*clkport &= ~clkpinmask;
if(d & bit) *mosiport |= mosipinmask;
else *mosiport &= ~mosipinmask;
*clkport |= clkpinmask;
}
#endif
}
}
bool Adafruit_PCD8544::isHardwareSPI() {
return (_din == -1 && _sclk == -1);
}
void Adafruit_PCD8544::command(uint8_t c) {
digitalWrite(_dc, LOW);
if (_cs > 0)
digitalWrite(_cs, LOW);
spiWrite(c);
if (_cs > 0)
digitalWrite(_cs, HIGH);
}
void Adafruit_PCD8544::data(uint8_t c) {
digitalWrite(_dc, HIGH);
if (_cs > 0)
digitalWrite(_cs, LOW);
spiWrite(c);
if (_cs > 0)
digitalWrite(_cs, HIGH);
}
void Adafruit_PCD8544::setContrast(uint8_t val) {
if (val > 0x7f) {
val = 0x7f;
}
command(PCD8544_FUNCTIONSET | PCD8544_EXTENDEDINSTRUCTION );
command( PCD8544_SETVOP | val);
command(PCD8544_FUNCTIONSET);
}
void Adafruit_PCD8544::display(void) {
uint8_t col, maxcol, p;
for(p = 0; p < 6; p++) {
#ifdef enablePartialUpdate
// check if this page is part of update
if ( yUpdateMin >= ((p+1)*8) ) {
continue; // nope, skip it!
}
if (yUpdateMax < p*8) {
break;
}
#endif
command(PCD8544_SETYADDR | p);
#ifdef enablePartialUpdate
col = xUpdateMin;
maxcol = xUpdateMax;
#else
// start at the beginning of the row
col = 0;
maxcol = LCDWIDTH-1;
#endif
command(PCD8544_SETXADDR | col);
digitalWrite(_dc, HIGH);
if (_cs > 0)
digitalWrite(_cs, LOW);
for(; col <= maxcol; col++) {
spiWrite(pcd8544_buffer[(LCDWIDTH*p)+col]);
}
if (_cs > 0)
digitalWrite(_cs, HIGH);
}
command(PCD8544_SETYADDR ); // no idea why this is necessary but it is to finish the last byte?
#ifdef enablePartialUpdate
xUpdateMin = LCDWIDTH - 1;
xUpdateMax = 0;
yUpdateMin = LCDHEIGHT-1;
yUpdateMax = 0;
#endif
}
// clear everything
void Adafruit_PCD8544::clearDisplay(void) {
memset(pcd8544_buffer, 0, LCDWIDTH*LCDHEIGHT/8);
updateBoundingBox(0, 0, LCDWIDTH-1, LCDHEIGHT-1);
cursor_y = cursor_x = 0;
}
/*
// this doesnt touch the buffer, just clears the display RAM - might be handy
void Adafruit_PCD8544::clearDisplay(void) {
uint8_t p, c;
for(p = 0; p < 8; p++) {
st7565_command(CMD_SET_PAGE | p);
for(c = 0; c < 129; c++) {
//uart_putw_dec(c);
//uart_putchar(' ');
st7565_command(CMD_SET_COLUMN_LOWER | (c & 0xf));
st7565_command(CMD_SET_COLUMN_UPPER | ((c >> 4) & 0xf));
st7565_data(0x0);
}
}
}
*/