The basement often smells a bit ‘humid’. To get a better idea of the exact degree of humidity, I want to perform continuous measurements during an entire year. Hopefully this will give me some insights about this ‘problem’. Based on the results I will:
- do nothing
- start an automated ventilation project
- start an automated ventilation project, combined with the installation of a ‘air-dryer’
The measurements will be done using an Arduino Uno, an Ethernet shield (holding a SD card slot) and some sensors to measure:
- inside temperature and humidity
- outside temperature and humidity
- inside floor and wall temperature
Arduino code:
/* Measure temperature and humidity over serveral sensors. Write about every x minutes the current readings to a text file on SD card. Each month, a new file will be generated. Allow to read current data via a webbrowser. Allow to download the log files via a webbrowser --> Todo. Format: comma-delimitted flat file Columns: - currentDateTime (YYYYMMDDHHMMSS) - Sensor 1 temperature (degrees Celcius) - Basement - Sensor 1 humidity (% relative humidity) - Basement - Sensor 2 temperature (degrees Celcius) - Garage --> Todo after POC (copy paste code) - Sensor 2 humidity (% relative humidity) - Garage --> Todo after POC (copy paste code) - Sensor 3 temperature (degrees Celcius) - Outdoor --> Todo after POC (copy paste code) - Sensor 3 humidity (% relative humidity) - Outdoor --> Todo after POC (copy past code) - API reading (extract from http://www.meteo.be/) temperature (degrees Celcius) official weather station nearby --> To be implemented. Not enough space on Uno. - API reading (extract from http://www.meteo.be/) humidity (% relative humidity) official weather station nearby --> To be implemented. Not enough space on Uno. - Sensor 4 temperature (degrees Celcius) - Floormounted (insulated) - Sensor 5 temperature (degrees Celcius) - Wallmounted (insulated) The circuit - DS1307 --> Arduino Uno - GND --> GND - VCC --> 3V - SDA --> A4 - SCL --> A5 - Sensor SHT15 #1 --> Arduino Uno: - GND --> GND - VCC --> VCC 5V (NOT 3V) - SDA --> A2 - SCL --> A3 - Sensor DS18B20 #1 --> Arduino Uno: - GND --> GND - VCC --> VCC 5V - SDA --> 4.7Kohm --> VCC 5V --> D8 (Shared data with other DS18B20 #2) - Sensor DS18B20 #2 --> Arduino Uno: - GND --> GND - VCC --> VCC 5V - SDA --> 4.7Kohm --> VCC 5V --> D8 (Shared data with DS18B20 #1) - Status LED 1: To be completed. - Status LED 2: To be completed. - Status LED 3: To be completed. Created 2017/09/23 By Maarten Van Damme Modified 2017/10/30 By Maarten Van Damme http://projects.familievandamme.be Based on samples: - https://www.arduino.cc/en/Tutorial/Datalogger - http://henrysbench.capnfatz.com/henrys-bench/arduino-sensors-and-input/arduino-tiny-rtc-d1307-tutorial/ ########################################################################################################################TODO: malloc function implement to free up memory of char arrays. */ #include <SPI.h> //Required for SD and Ethernet #include <SD.h> // Required for SD #include <Wire.h> //Required for RTC #include <RTClib.h> // Required for RTC #include <SHT1X.h> //Required for DHT15 #include <OneWire.h> //Required for DS18B20 #include <DallasTemperature.h> //Required for DS18B20 #include <Ethernet.h> //Required for Webserver //#include <dht.h> //Required for DHT11 //#define DHT11_PIN 7 #define RTCStatusLedGreen 2 #define RTCStatusLedRed 3 #define SDStatusLedGreen 5 #define SDStatusLedRed 6 #define WriteStatusLedBlue 7 #define DS18B20_ONE_WIRE_PIN 8 //Multiple sensors can be handled on the same pin #define WriteStatusLedRed 9 #define chipSelectSD 4 //to select SD card //#define chipSelectEthernet 10 // to select Ethernet #define cycleTime 10 RTC_DS1307 RTC;//Real time clock //dht DHT; //Create an instance of the SHT1X sensor SHT1x SF_SHT15_1(A2, A3);//Data, SCK --> Ensure the DHT15 gets 5V, 3.3V does weird things!!! //Setup a oneWire instance to communicate with any OneWire devices OneWire DS18B20_ONE_WIRE(DS18B20_ONE_WIRE_PIN); DallasTemperature DS18B20_SENSORS(&DS18B20_ONE_WIRE); //Setup webserver byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; IPAddress ip(192, 168, 1, 177); EthernetServer server(80); //Keep track of any errors encountered along the way boolean SDCardWriteErrors = false; boolean readyForNextIteration = true; boolean firstRun = true; void setup() { //Define status LEDs pinMode(RTCStatusLedRed, OUTPUT); pinMode(RTCStatusLedGreen, OUTPUT); pinMode(SDStatusLedRed, OUTPUT); pinMode(SDStatusLedGreen, OUTPUT); pinMode(WriteStatusLedBlue, OUTPUT); pinMode(WriteStatusLedRed, OUTPUT); // Open serial communications and wait for port to open: Serial.begin(9600); // wait for serial port to connect. Needed for native USB port only while (!Serial) { ; //Just wait until done (only works on Leonardo, not on Uno) } Wire.begin(); RTC.begin(); // Check to see if the RTC is keeping time. If it is, load the time from your computer. if (! RTC.isrunning()) { Serial.println("RTC is not running!"); digitalWrite(RTCStatusLedRed, HIGH); // Set the current time to the current compilation time. RTC.adjust(DateTime(__DATE__, __TIME__)); } else { digitalWrite(RTCStatusLedGreen, HIGH); } // Verify if the SD card is present and can be initialized Serial.print("Initializing SD card..."); if (!SD.begin(chipSelectSD)) { Serial.println("SD card init failed, or not present"); digitalWrite(SDStatusLedRed, HIGH); stop();//No use continuing if things go bad at startup } else { Serial.println(F("SD card initialized.")); digitalWrite(SDStatusLedGreen, HIGH); } DS18B20_SENSORS.begin(); Ethernet.begin(mac, ip); server.begin(); Serial.print(F("server is at ")); Serial.println(Ethernet.localIP()); } void loop() { DateTime currentDateTime = RTC.now(); //char dht11_1_temperature[7]; //char dht11_1_humidity[7]; char dht15_1_temperature[7]; char dht15_1_humidity[7]; char DS18B20_1_temperature[7]; char DS18B20_2_temperature[7]; char timestamp_YYYYMMDDHHMMSS[20]; if (currentDateTime.minute() % cycleTime == 0 and readyForNextIteration or firstRun) //Run every x minutes ONCE, excluding first run { //Read DHT11 //int chk = DHT.read11(DHT11_PIN); DS18B20_SENSORS.requestTemperatures(); char csvLine[100] = ""; //dtostrf(DHT.temperature, 5 , 2, dht11_1_temperature); //dtostrf(DHT.humidity, 5 , 2, dht11_1_humidity); dtostrf(SF_SHT15_1.readTemperatureC(), 5 , 2, dht15_1_temperature); dtostrf(SF_SHT15_1.readHumidity(), 5 , 2, dht15_1_humidity); dtostrf(DS18B20_SENSORS.getTempCByIndex(0), 5 , 2, DS18B20_1_temperature); dtostrf(DS18B20_SENSORS.getTempCByIndex(1), 5 , 2, DS18B20_2_temperature); char timestamp_YYYYMM[6];//To construct file name. //consider using dtostrf instead of sprintf sprintf(timestamp_YYYYMMDDHHMMSS, "%04d/%02d/%02d %02d:%02d:%02d", currentDateTime.year(), currentDateTime.month(), currentDateTime.day(), currentDateTime.hour(), currentDateTime.minute(), currentDateTime.second()); //consider using dtostrf instead of sprintf sprintf(timestamp_YYYYMM, "%04d%02d", currentDateTime.year(), currentDateTime.month()); //Constructing output strcat(csvLine, timestamp_YYYYMMDDHHMMSS); strcat(csvLine, ","); strcat(csvLine, dht15_1_temperature); strcat(csvLine, ","); strcat(csvLine, dht15_1_humidity); strcat(csvLine, ","); strcat(csvLine, DS18B20_1_temperature); strcat(csvLine, ","); strcat(csvLine, DS18B20_2_temperature); Serial.println(csvLine); char csvFileName[15]; //consider using dtostrf instead of sprintf sprintf(csvFileName, "%s%s%s", "H", timestamp_YYYYMM, ".txt"); //Open a file on the SD card. If the file is opened for writing, it will be created if it doesn't already exist // /* //This part works perfectly as long as the ethernet code is not active. //Probably it has something to do with the SS pins ... and bad support of the current arduino clone shield File csvFile = SD.open(csvFileName, FILE_WRITE); // If the CSV file is available, write data to it if (csvFile) { csvFile.println(csvLine); csvFile.close(); led_blink(WriteStatusLedBlue); Serial.println(csvLine);//For testing only } // If sh*t hits the fan... else { Serial.print(F("\nCannot access file or SD card. ")); Serial.print(F("Ensure a valid file name is used. e.g. FAT16 can only handle 8.3 type file names! ")); Serial.print(F("Current file name: " )); Serial.print(csvFileName); Serial.println(F(".")); SDCardWriteErrors = true; } // */ //Ensure the code doesn't run multiple times within the same minute readyForNextIteration = false; firstRun = false; } else { //Todo: implement trigger events such as opening doors... } //Enable next iteration one the 10 minute cycle has passed if (currentDateTime.minute() % cycleTime != 0) { readyForNextIteration = true; } // listen for incoming clients EthernetClient client = server.available(); if (client) { // A http request ends with a blank line boolean currentLineIsBlank = true; while (client.connected()) { if (client.available()) { char c = client.read(); Serial.write(c); // if you've gotten to the end of the line (received a newline // character) and the line is blank, the http request has ended, // so you can send a reply if (c == '\n' && currentLineIsBlank) { // send a standard http response header client.println(F("HTTP/1.1 200 OK")); client.println("Content-Type: text/html"); client.println("Connection: close"); // Ensure the connection will be closed after completion of the response client.println("Refresh: 60"); client.println(); client.println("<!DOCTYPE HTML>"); client.println("<html>"); client.println(F("<h1>Basement humidity measurement.</h1>")); client.println(F("<p>Last measurement: <b>")); client.println(timestamp_YYYYMMDDHHMMSS); client.println(F("</b>")); client.println(F("<p>")); client.println(F("<p>DHT15 - Temperature: <b>")); client.println(dht15_1_temperature); client.println(F("°C</b>")); client.println(F("<p>")); client.println(F("<p>DHT15 - Humidity: <b>")); client.println(dht15_1_humidity); client.println(F("%RH</b>")); client.println(F("<p>")); client.println(F("<p>DS18B20 #1 - Temperature: <b>")); client.println(DS18B20_1_temperature); client.println(F("°C</b>")); client.println(F("<p>")); client.println(F("<p>")); client.println(F("<p>DS18B20 #2 - Temperature: <b>")); client.println(DS18B20_2_temperature); client.println(F("°C</b>")); client.println(F("<p>")); client.println(F("</html>")); break; } if (c == '\n') { // you're starting a new line currentLineIsBlank = true; } else if (c != '\r') { // you've gotten a character on the current line currentLineIsBlank = false; } } } // give the web browser time to receive the data delay(1); // close the connection: client.stop(); Serial.println("client disconnected"); } //Indicate if along the way something went wrong since the last 'reboot'. digitalWrite(WriteStatusLedRed, SDCardWriteErrors); } //Turn led on and off rapidly few times void led_blink(int ledPin) { for (int i = 0; i < 20; i++) { digitalWrite(ledPin, HIGH); delay(100); digitalWrite(ledPin, LOW); delay(100); } } //Create endless loop void stop() { while (true) { delay(1000); } } // Print DS18B20 serial number (handy when multiple sensors are connected to the same data line). /* void printSerialNumber(byte *addr) { byte i; for ( i = 0; i < 8; i++) { Serial.print(F("0x")); if (addr[i] < 16) { Serial.print('0'); } Serial.print(addr[i], HEX); if (i < 7) { Serial.print(F(", ")); } } } */
Sources:
- Data logger: https://www.arduino.cc/en/Tutorial/Datalogger
- Tiny RTC: http://henrysbench.capnfatz.com/henrys-bench/arduino-sensors-and-input/arduino-tiny-rtc-d1307-tutorial/