ESP8266/DHT
Humidity/Temperature sensor with SD Card data logger.
Note: Requires modified Nokia library.
#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_PUSH 0 // Push Button Switch
#define PIN_SD_CS 10 // Make sure "DIO" is selected
#define PIN_SOUND 3 // Piezo, overlapped with Serial Rx
//You may find a different size screen, but this one is 84 by 48 pixels
#define LCD_X 84
#define LCD_Y 48
#define LINE_INTERVAL 200
#define PING_INTERVAL 1000
#define MODE_HUMIDITY 16
#define MODE_SOUND 1
#define MODE_PING 2
#define MODE_CARD 3
#define MODE_FILE 4
#define MODE_CONTRAST 5
#define MODE_FIRMWARE 6
#define MODE_INITIALIZE 255
#define SWITCH_DEBOUNCE_TIME 50 // Timeout for debouncing presses
#define SWITCH_MULTI_TIME 300 // Timeout for detecting multiple clicks
#define SWITCH_HOLD_TIME 2000 // Timeout for detecting press and hold
#define SWITCH_PRESS 1
#define SWITCH_RELEASE 2
#define SWITCH_MULTI 4
#define SWITCH_HOLD 8
#define DISPLAY_ENABLED true
// set up variables using the SD utility library functions:
Sd2Card card;
SdVolume volume;
SdFile root;
bool sdEnabled = false;
unsigned long nextLineMillis = 0;
unsigned long nextPing = 0;
unsigned long pingMillis = 0;
unsigned long debounceMillis = 0;
unsigned long doubleMillis = 0;
unsigned long holdMillis = 0;
int lastPing = 0;
bool pushStateOn = false;
uint8_t activeMode = MODE_INITIALIZE;
uint8_t clickCount = 0;
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 setup() {
pinMode(PIN_PUSH, INPUT_PULLUP);
pinMode(PIN_SOUND, OUTPUT);
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.println("WiFi: " + String(ssid).substring(0, 7));
display.display();
}
// WiFi.begin(ssid, password);
WiFi.begin();
unsigned long timeout = millis() + 10000;
while (WiFi.status() != WL_CONNECTED){
digitalWrite(5, HIGH);
delay(50);
digitalWrite(5, LOW);
delay(450);
// Serial.printf(".\n");
if (millis() > timeout)
break;
}
wifiEnabled = WiFi.status() == WL_CONNECTED;
if (wifiEnabled) {
// Port defaults to 8266
// ArduinoOTA.setPort(8266);
// Hostname defaults to esp8266-[ChipID]
// ArduinoOTA.setHostname("myesp8266");
// No authentication by default
// ArduinoOTA.setPassword((const char *)"123");
ArduinoOTA.onStart([]() {
// Serial.println("Start");
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.onEnd([]() {
// Serial.println("\nEnd");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
static uint8_t lastProgress = 0;
static unsigned long nextTime = 0;
uint8_t p = (progress / (total / 100));
// Serial.printf("Progress: %u%%\r", p);
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 {
// Serial.println("Start");
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) {
// Serial.printf("Error[%u]: ", error);
// if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
// else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
// else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
// else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
// else if (error == OTA_END_ERROR) Serial.println("End Failed");
if (DISPLAY_ENABLED) {
display.println("ERROR: " + String(error));
display.display();
delay(1000);
}
});
ArduinoOTA.begin();
// Serial.println("Ready");
// Serial.print("IP address: ");
// Serial.println(WiFi.localIP());
if (DISPLAY_ENABLED) {
display.println(WiFi.localIP());
display.display();
}
for (int i = 0; i < 10; i++) {
ArduinoOTA.handle();
delay(100);
yield();
}
}
//TODO - change delay to loop funtion
if(!SD.begin(PIN_SD_CS)) {
//no SD found
display.clearDisplay();
display.println("No SD found");
display.display();
delay(1000);
} else {
//SD initialized
sdEnabled = true;
}
dht.begin();
setMode(MODE_HUMIDITY);
}
void loop() {
if (wifiEnabled)
ArduinoOTA.handle();
unsigned long now = millis();
bool pushed = !digitalRead(PIN_PUSH);
uint8_t buttonAction = 0;
if (client.connected()) {
bool got = checkGet();
if (got) {
lastPing = millis() - pingMillis;
nextPing = millis() + PING_INTERVAL;
}
} else if (millis() > nextPing) {
sendGet();
}
// Handle switch state(s)
if (now > debounceMillis && pushed != pushStateOn) {
// Push switch state change
debounceMillis = now + SWITCH_DEBOUNCE_TIME;
if (pushed) {
// Switch pushed
pushStateOn = true;
if (doubleMillis < now) {
doubleMillis = now + SWITCH_MULTI_TIME;
clickCount = 1;
// string2Line("Switch: ON", 4);
buttonAction = SWITCH_PRESS;
} else {
// Multi-click, goto next mode
setMode(activeMode < 5 ? activeMode + 1 : 0);
clickCount++;
// string2Line("Mode: " + String(activeMode), 2);
// string2Line("Click: " + String(clickCount), 4);
buttonAction = SWITCH_MULTI;
}
holdMillis = now + SWITCH_HOLD_TIME;
} else {
// Switch released
pushStateOn = false;
// string2Line("Switch: OFF", 4);
holdMillis = 0;
buttonAction = SWITCH_RELEASE;
}
} else if (pushed && holdMillis > 0 && now > holdMillis) {
// Long press
// string2Line("Switch: HOLD", 4);
holdMillis = 0;
buttonAction = SWITCH_HOLD;
}
if (activeMode == MODE_HUMIDITY) {
handleHumidity();
} else if (activeMode == MODE_PING) {
handlePingMode(buttonAction);
} else if (activeMode == MODE_CARD) {
handleCardMode(buttonAction);
} else if (activeMode == MODE_FILE) {
handleFileMode(buttonAction);
} else if (activeMode == MODE_FIRMWARE) {
handleFirmwareMode(buttonAction);
} else if (activeMode == MODE_CONTRAST) {
handleContrastMode();
} else if (activeMode == MODE_SOUND) {
handleSoundMode(buttonAction);
}
int a = analogRead(A0) / 4;
if (a > 255)
a = 255;
analogWrite(4, a);
// analogWrite(5, digitalRead(0) ? 0 : 127);
delay(50);
}
void setMode(uint8_t newMode) {
if (newMode != activeMode) {
if (DISPLAY_ENABLED) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(28, 0);
display.println("mode:");
display.setCursor(32, 12);
display.setTextSize(3);
display.println(newMode);
display.display();
delay(300);
yield();
}
if (newMode == MODE_PING) {
handlePingMode(0);
} else if (newMode == MODE_CARD) {
handleCardMode(SWITCH_HOLD);
} else if (newMode == MODE_FILE) {
handleFileMode(SWITCH_PRESS);
} else if (newMode == MODE_FIRMWARE) {
handleFirmwareMode(0);
} else if (newMode == MODE_CONTRAST) {
handleContrastMode();
} else if (newMode == MODE_SOUND) {
handleSoundMode(SWITCH_RELEASE);
}
activeMode = newMode;
} else {
// Not a new mode selection
}
}
void handleHumidity() {
static unsigned long next = 5000;
unsigned long now = millis();
if (now > next) {
next = now + 2000;
int h, c, f;
h = dht.readHumidity();
c = dht.readTemperature();
f = dht.readTemperature(true);
display.clearDisplay();
display.setCursor(0, 0);
display.setTextSize(2);
display.println(String(c) + "/" + String(f));
display.setTextSize(3);
display.println(String(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();
}
}
digitalWrite(5, HIGH);
delay(200);
digitalWrite(5, LOW);
}
}
void handlePingMode(uint8_t action) {
if (client.connected()) {
bool got = checkGet();
if (got) {
lastPing = millis() - pingMillis;
nextPing = millis() + PING_INTERVAL;
// Serial.println("Ping: " + String(lastPing) + "ms");
}
} else if (action == SWITCH_PRESS && millis() > nextPing) {
// Do new ping on switch press
sendGet();
}
// Check/show signal strength
if (millis() > nextLineMillis) {
int signalStrength = WiFi.RSSI() >= -50 ? 100 : 2 * (WiFi.RSSI() + 100);
String signalBars = " ";
nextLineMillis = millis() + LINE_INTERVAL;
if (DISPLAY_ENABLED) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(0, 0);
for (int i = 0; i < signalStrength / 10; i++)
signalBars += "*";
display.println(signalBars);
display.println(String(WiFi.RSSI()) + "db/" + String(signalStrength) + "%");
display.println();
display.println("Ping: " + String(lastPing) + "ms");
display.println();
display.println("#007 " + String(millis() / 1000));
display.display();
}
}
}
void handleCardMode(uint8_t action) {
if (action == SWITCH_HOLD)
testSD();
}
void handleFileMode(uint8_t action) {
if (action == SWITCH_PRESS)
getNextFile();
}
void handleFirmwareMode(uint8_t action) {
digitalWrite(PIN_SD_CS, digitalRead(2));
}
void handleContrastMode() {
static uint8_t contrast = 50;
uint8_t analog = analogRead(A0) / 8;
if (!DISPLAY_ENABLED)
return;
if (analog != contrast) {
contrast = analog;
display.clearDisplay();
display.setCursor(0, 0);
display.setTextSize(1);
display.println(" Contrast:");
display.setTextSize(3);
display.println(contrast);
display.setContrast(contrast);
display.display();
}
yield();
delay(50);
}
void handleSoundMode(uint8_t action) {
static bool soundOn = false;
static int frequency = 1000;
static int duty = 512;
bool refresh = action != 0;
if (action == SWITCH_HOLD) {
// Toggle sound on
soundOn = !soundOn;
if (soundOn) {
analogWrite(PIN_SOUND, duty);
} else {
analogWrite(PIN_SOUND, 0);
}
} else if (action == SWITCH_PRESS) {
frequency = analogRead(A0) * 4;
// Crash if set to 0, espressif PWM defined as 100Hz-1Khz
if (frequency < 10) frequency = 10;
analogWriteFreq(frequency);
}
if (!digitalRead(2)) {
// Right switch pressed
duty = analogRead(A0);
if (soundOn)
analogWrite(PIN_SOUND, duty);
refresh = true;
}
if (refresh) {
display.clearDisplay();
display.setCursor(0, 0);
display.setTextSize(1);
display.println(" Sound: " + String(soundOn ? "ON" : "OFF") + "\r\n");
display.setTextSize(2);
display.println((frequency < 100 ? " " : "") + String(frequency) + "Hz");
display.println(" " + String(int(duty / 10.24)) + "%");
display.display();
}
yield();
delay(50);
}
void sendGet() {
pingMillis = millis();
if (!client.connect("void-local.tablesugar.info", 80)) {
// Error
return;
}
client.print("GET /none.html HTTP/1.1\r\nHost: void-local.tablesugar.info\r\nConnection: close\r\n\r\n");
}
bool checkGet() {
if (client.available()) {
// Got something
client.stop();
return true;
} else if (millis() - pingMillis > 2000) {
// Timeout
client.stop();
return true;
}
return false;
}
void testSD() {
// Serial.print("\nInitializing SD card...");
if (DISPLAY_ENABLED) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(0, 0);
display.println("*Testing SD*");
display.display();
}
// we'll use the initialization code from the utility libraries
// since we're just testing if the card is working!
// if (!card.init(SPI_HALF_SPEED, PIN_SD_CS)) {
if (!card.init(400000, PIN_SD_CS)) {
// Serial.println("initialization failed. Things to check:");
// Serial.println("* is a card inserted?");
// Serial.println("* is your wiring correct?");
// Serial.println("* did you change the PIN_SD_CS pin to match your shield or module?");
if (DISPLAY_ENABLED) {
display.println("NO CARD!!!");
display.display();
}
return;
} else {
// Serial.println("Wiring is correct and a card is present.");
// string2Line("Card found", 1);
nextLineMillis = nextPing = 5000;
}
// print the type of card
// Serial.print("\nCard type: ");
String cardType;
switch (card.type()) {
case SD_CARD_TYPE_SD1:
cardType = "SD1";
break;
case SD_CARD_TYPE_SD2:
cardType = "SD2";
break;
case SD_CARD_TYPE_SDHC:
cardType = "SDHC";
break;
// default:
// Serial.println("????");
}
// Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
if (!volume.init(card)) {
// Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
// Serial.println(cardType);
if (DISPLAY_ENABLED) {
display.println("No partition\r\nFAT16/FAT32\r\nfmt needed.");
display.display();
}
return;
}
// print the type and size of the first FAT-type volume
uint32_t volumesize;
// Serial.print("\nVolume type is FAT");
// Serial.println(volume.fatType(), DEC);
// Serial.println();
// Serial.println(cardType);
if (DISPLAY_ENABLED)
display.println(cardType + "/FAT" + String(volume.fatType()));
volumesize = volume.blocksPerCluster(); // clusters are collections of blocks
volumesize *= volume.clusterCount(); // we'll have a lot of clusters
volumesize *= 512; // SD card blocks are always 512 bytes
// Serial.print("Volume size (bytes): ");
// Serial.println(volumesize);
// Serial.print("Volume size (Kbytes): ");
volumesize /= 1024;
// Serial.println(volumesize);
// Serial.print("Volume size (Mbytes): ");
volumesize /= 1024;
// Serial.println(volumesize);
if (volumesize < 1000) {
if (DISPLAY_ENABLED)
display.println("Size: " + String(volumesize) + "MB");
} else {
if (DISPLAY_ENABLED)
display.println("Size: " + String(round(volumesize / 100) / 10) + "GB");
}
if (DISPLAY_ENABLED)
display.display();
// Serial.println("\nFiles found on the card (name, date and size in bytes): ");
root.openRoot(volume);
// list all files in the card with date and size
root.ls(LS_R | LS_DATE | LS_SIZE);
}
void getNextFile() {
static bool inited = false;
static int fileCount = 0;
// Serial.println("Get files...");
if (DISPLAY_ENABLED) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(0, 0);
display.print("SD: " + String(fileCount) + " ");
display.display();
}
if (!inited && !SD.begin(PIN_SD_CS)) {
// Serial.println("Initialization failed!");
if (DISPLAY_ENABLED) {
display.println("Initializat-\r\nion failed!");
display.display();
}
return;
}
inited = true;
File files = SD.open("/");
File file;
unsigned long fileSize;
int index = 0;
while (true) {
file = files.openNextFile();
if (!file) {
// end
// Serial.println("end of files");
if (DISPLAY_ENABLED)
display.println("end of files");
display.display();
fileCount = 0;
return;
}
if (!file.isDirectory()) {
if (index == fileCount) {
// name of next file
// Serial.print(String(file.name()));
fileSize = file.size();
if (fileSize < 1024) {
if (DISPLAY_ENABLED)
display.print(String(fileSize) + "Bytes");
} else if (fileSize < 100000) {
if (DISPLAY_ENABLED)
display.print(String(round(file.size() / 1024)) + "KB");
} else {
if (DISPLAY_ENABLED)
display.print(String(round(file.size() / 1024 / 10.24) / 100.0) + "MB");
}
if (DISPLAY_ENABLED)
display.println("\r\n" + String(file.name()));
fileCount++;
break;
}
index++;
}
}
String fileContent = "";
while (file.available() && fileContent.length() < 36) {
fileContent += char(file.read());
}
while (fileContent.length() < 64)
fileContent += " ";
if (DISPLAY_ENABLED)
display.println(fileContent);
display.display();
}