├── ESP8266-SHT21-HTU21-BMP180-DHT22-Thingspeak-logger.ino ├── README.md └── logger_picture_1.jpg /ESP8266-SHT21-HTU21-BMP180-DHT22-Thingspeak-logger.ino: -------------------------------------------------------------------------------- 1 | /**The MIT License (MIT) 2 | Copyright (c) 2015 by Daniel Eichhorn 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | The above copyright notice and this permission notice shall be included in all 10 | copies or substantial portions of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 17 | SOFTWARE. 18 | thanks to Dani Eichhorn -> http://blog.squix.ch 19 | 20 | * This sketch sends data via HTTP GET requests to thingspeak service every 10 minutes 21 | * You have to set your wifi credentials and your thingspeak key. 22 | * Arduino 1.65 23 | * added humidex, heatindex, dewpoint, battery voltage 24 | */ 25 | 26 | #include //https://github.com/adafruit/Adafruit-BMP085-Library V1.0 27 | #include 28 | #include 29 | #include 30 | extern "C" { 31 | #include "user_interface.h" 32 | } 33 | #include "DHT.h" //https://github.com/adafruit/DHT-sensor-library V1.2.3 34 | 35 | #define DHTPIN 12 // what pin we're connected to 36 | 37 | // Uncomment whatever type you're using! 38 | //#define DHTTYPE DHT11 // DHT 11 39 | #define DHTTYPE DHT22 // DHT 22 (AM2302) 40 | //#define DHTTYPE DHT21 // DHT 21 (AM2301) 41 | 42 | DHT dht(DHTPIN, DHTTYPE, 15); 43 | 44 | // for HTDU21D 45 | #define HTDU21D_ADDRESS 0x40 //Unshifted 7-bit I2C address for the sensor 46 | #define TRIGGER_TEMP_MEASURE_HOLD 0xE3 47 | #define TRIGGER_HUMD_MEASURE_HOLD 0xE5 48 | #define TRIGGER_TEMP_MEASURE_NOHOLD 0xF3 49 | #define TRIGGER_HUMD_MEASURE_NOHOLD 0xF5 50 | #define WRITE_USER_REG 0xE6 51 | #define READ_USER_REG 0xE7 52 | #define SOFT_RESET 0xFE 53 | 54 | Adafruit_BMP085 bmp; // Create the bmp object 55 | int altitude = 385; // Höhe des Sensorstandortes ueber dem Meeresspiegel 56 | 57 | const char* ssid = "XXXXXXXXXXXX"; 58 | const char* password = "XXXXXXXXXXXX"; 59 | 60 | 61 | const char* host = "api.thingspeak.com"; 62 | const char* thingspeak_key = "XXXXXXXXXXXX"; //write key 63 | 64 | void turnOff(int pin) { 65 | pinMode(pin, OUTPUT); 66 | digitalWrite(pin, 1); 67 | } 68 | 69 | void setup() { 70 | Serial.begin(115200); 71 | Wire.begin(4, 5); // i2C SDA D2, SCL D1 72 | Wire.setClock(400000); 73 | if (!bmp.begin()) { 74 | Serial.println("Could not find a valid BMP085 sensor, check wiring!"); 75 | while (1) {} 76 | } 77 | 78 | // disable all unused outputs to save power 79 | turnOff(0); 80 | turnOff(2); 81 | turnOff(12); 82 | turnOff(13); 83 | turnOff(14); 84 | turnOff(15); 85 | 86 | dht.begin(); 87 | delay(10); 88 | 89 | 90 | // We start by connecting to a WiFi network 91 | 92 | Serial.println(); 93 | Serial.println(); 94 | Serial.print("Connecting to "); 95 | Serial.println(ssid); 96 | 97 | WiFi.begin(ssid, password); 98 | 99 | while (WiFi.status() != WL_CONNECTED) { 100 | delay(500); 101 | Serial.print("."); 102 | } 103 | 104 | Serial.println(""); 105 | Serial.println("WiFi connected"); 106 | Serial.println("IP address: "); 107 | Serial.println(WiFi.localIP()); 108 | } 109 | 110 | int value = 0; 111 | 112 | int r1 = 3300; //Voltage Divider (220k on board added 110k from Battery + to A0 pin) 113 | int r2 = 1000; //Voltage Divider (100k on board) 114 | int vref = 980; //Internal vref of your Nodemcu/WEMOS D1 mini alternativ 985 115 | 116 | 117 | void loop() { 118 | delay(5000); 119 | ++value; 120 | 121 | Serial.print("connecting to "); 122 | Serial.println(host); 123 | 124 | // Use WiFiClient class to create TCP connections 125 | WiFiClient client; 126 | const int httpPort = 80; 127 | if (!client.connect(host, httpPort)) { 128 | Serial.println("connection failed"); 129 | return; 130 | } 131 | unsigned int rawHumidity = htdu21d_readHumidity(); 132 | unsigned int rawTemperature = htdu21d_readTemp(); 133 | //String temp = String(dht.readTemperature()); 134 | //String humidity = String(dht.readHumidity()); 135 | String pressure = String(bmp.readSealevelPressure(altitude)/100.0F); // pressure in hPA/mBar , ohne nachkommastellen = (bmp.readSealevelPressure(altitude)/100.0F, 0); 136 | String lux = String(getLux()); 137 | String shttemp = String (calc_temp(rawTemperature)); 138 | String shthum = String (calc_humidity(rawHumidity)); 139 | String dewpoint = String (dewPoint(calc_temp(rawTemperature), (calc_humidity(rawHumidity)))); 140 | String shttempfahrenheit = String (Fahrenheit(calc_temp(rawTemperature))); 141 | float h = (calc_humidity(rawHumidity)); 142 | float t = (calc_temp(rawTemperature)); 143 | float f = (Fahrenheit(calc_temp(rawTemperature))); 144 | float hi = dht.computeHeatIndex(f, h); 145 | float heatindex = dht.convertFtoC(hi); 146 | float humidex = calculate_humidex (t, h); 147 | float adc_value = analogRead(A0); //adc.read(0) 148 | float battery = vref * (adc_value) * (r1 + r2) / r2 / 1024 / 1000; 149 | 150 | 151 | String url = "/update?key="; 152 | url += thingspeak_key; 153 | url += "&field1="; 154 | url += shttemp; 155 | url += "&field2="; 156 | url += shthum; 157 | url += "&field3="; 158 | url += pressure; 159 | url += "&field4="; 160 | url += lux; 161 | url += "&field5="; 162 | url += dewpoint; 163 | url += "&field6="; 164 | url += heatindex; 165 | url += "&field7="; 166 | url += humidex; 167 | url += "&field8="; 168 | url += battery; 169 | 170 | 171 | Serial.print("Requesting URL: "); 172 | Serial.println(url); 173 | 174 | // This will send the request to the server 175 | client.print(String("GET ") + url + " HTTP/1.1\r\n" + 176 | "Host: " + host + "\r\n" + 177 | "Connection: close\r\n\r\n"); 178 | delay(10); 179 | 180 | // Read all the lines of the reply from server and print them to Serial 181 | while(client.available()){ 182 | String line = client.readStringUntil('\r'); 183 | Serial.print(line); 184 | } 185 | 186 | Serial.println(); 187 | Serial.println("closing connection. going to sleep..."); 188 | delay(1000); 189 | // go to deepsleep for 10 minutes 190 | 191 | //WAKE_RF_DEFAULT = 0, // RF_CAL or not after deep-sleep wake up, depends on init data byte 108. 192 | //WAKE_RFCAL = 1, // RF_CAL after deep-sleep wake up, there will be large current. 193 | //WAKE_NO_RFCAL = 2, // no RF_CAL after deep-sleep wake up, there will only be small current. 194 | //WAKE_RF_DISABLED = 4 // disable RF after deep-sleep wake up, just like modem sleep, there will be the smallest current. 195 | //ESP.deepSleep(10 * 60 * 1000000, WAKE_RF_DEFAULT); // GPIO16 needs to be tied to RST to wake from deepSleep. 196 | system_deep_sleep_set_option(0); // GPIO16/D0 needs to be tied to RST to wake from deepSleep. 197 | system_deep_sleep(10 * 60 * 1000000); 198 | } 199 | 200 | //Celsius to Fahrenheit conversion 201 | double Fahrenheit(double celsius) 202 | { 203 | return 1.8 * celsius + 32; 204 | } 205 | 206 | // fast integer version with rounding 207 | //int Celcius2Fahrenheit(int celcius) 208 | //{ 209 | // return (celsius * 18 + 5)/10 + 32; 210 | //} 211 | 212 | //Fahrenheit to Celsius conversion 213 | double Celsius(double Fahrenheit) 214 | { 215 | return (Fahrenheit - 32) * 0.55555; 216 | } 217 | 218 | 219 | //Celsius to Kelvin conversion 220 | double Kelvin(double celsius) 221 | { 222 | return celsius + 273.15; 223 | } 224 | 225 | // dewPoint function NOAA 226 | // reference (1) : http://wahiduddin.net/calc/density_algorithms.htm 227 | // reference (2) : http://www.colorado.edu/geography/weather_station/Geog_site/about.htm 228 | // 229 | double dewPoint(double celsius, double humidity) 230 | { 231 | // (1) Saturation Vapor Pressure = ESGG(T) 232 | double RATIO = 373.15 / (273.15 + celsius); 233 | double RHS = -7.90298 * (RATIO - 1); 234 | RHS += 5.02808 * log10(RATIO); 235 | RHS += -1.3816e-7 * (pow(10, (11.344 * (1 - 1/RATIO ))) - 1) ; 236 | RHS += 8.1328e-3 * (pow(10, (-3.49149 * (RATIO - 1))) - 1) ; 237 | RHS += log10(1013.246); 238 | 239 | // factor -3 is to adjust units - Vapor Pressure SVP * humidity 240 | double VP = pow(10, RHS - 3) * humidity; 241 | 242 | // (2) DEWPOINT = F(Vapor Pressure) 243 | double T = log(VP/0.61078); // temp var 244 | return (241.88 * T) / (17.558 - T); 245 | } 246 | 247 | // delta max = 0.6544 wrt dewPoint() 248 | // 6.9 x faster than dewPoint() 249 | // reference: http://en.wikipedia.org/wiki/Dew_point 250 | double dewPointFast(double celsius, double humidity) 251 | { 252 | double a = 17.271; 253 | double b = 237.7; 254 | double temp = (a * celsius) / (b + celsius) + log(humidity*0.01); 255 | double Td = (b * temp) / (a - temp); 256 | return Td; 257 | } 258 | 259 | //function to calculete Humidex 260 | 261 | float calculate_humidex(float temperature,float humidity) { 262 | float e; 263 | 264 | e = (6.112 * pow(10,(7.5 * temperature/(237.7 + temperature))) * humidity/100); //vapor pressure 265 | 266 | float humidex = temperature + 0.55555555 * (e - 10.0); //humidex 267 | return humidex; 268 | 269 | } 270 | 271 | //--------------------------------- Light intensity 272 | float getLux(){ 273 | byte dmsb,dlsb; 274 | float lx; 275 | 276 | // BH1750 address is 0x5c or 0x23 277 | 278 | Wire.beginTransmission(0x23); 279 | Wire.write(0x11); // high res 2 continuous (.5 lx res) 280 | Wire.endTransmission(); 281 | delay(200); // wait 180ms max to complete conversion 282 | Wire.beginTransmission(0x23); 283 | Wire.requestFrom(0x23,2); 284 | dmsb=Wire.read(); 285 | dlsb=Wire.read(); 286 | Wire.endTransmission(); 287 | // we need to futz a bit because bit 0 is a .5 indicator 288 | lx=dmsb<<8; 289 | if (dlsb & 1){ 290 | lx=lx+0.5; 291 | } 292 | dlsb=(dlsb>>1); // dump the decimal 293 | lx=lx+dlsb; 294 | lx=lx/1.2; 295 | return(lx); 296 | } 297 | 298 | //--------------------------------- Temperature and Humidity 299 | /* 300 | HTU21D Humidity Sensor Example Code 301 | By: Nathan Seidle 302 | SparkFun Electronics 303 | Date: September 15th, 2013 304 | License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license). 305 | */ 306 | //Read the uncompensated temperature value 307 | unsigned int htdu21d_readTemp() 308 | { 309 | //Request the temperature 310 | Wire.beginTransmission(HTDU21D_ADDRESS); 311 | Wire.write(TRIGGER_TEMP_MEASURE_NOHOLD); 312 | Wire.endTransmission(); 313 | 314 | //Wait for sensor to complete measurement 315 | //delay(60); //44-50 ms max - we could also poll the sensor 316 | delay(95); 317 | 318 | //Comes back in three bytes, data(MSB) / data(LSB) / CRC 319 | Wire.requestFrom(HTDU21D_ADDRESS, 3); 320 | 321 | //Wait for data to become available 322 | int counter = 0; 323 | while(Wire.available() < 3) 324 | { 325 | counter++; 326 | delay(1); 327 | if(counter > 100) return 998; //Error out 328 | } 329 | 330 | unsigned char msb, lsb, crc; 331 | msb = Wire.read(); 332 | lsb = Wire.read(); 333 | crc = Wire.read(); //We don't do anything with CRC for now 334 | 335 | unsigned int temperature = ((unsigned int)msb << 8) | lsb; 336 | temperature &= 0xFFFC; //Zero out the status bits but keep them in place 337 | 338 | return temperature; 339 | } 340 | 341 | //Read the humidity 342 | unsigned int htdu21d_readHumidity() 343 | { 344 | byte msb, lsb, checksum; 345 | 346 | //Request a humidity reading 347 | Wire.beginTransmission(HTDU21D_ADDRESS); 348 | Wire.write(TRIGGER_HUMD_MEASURE_NOHOLD); //Measure humidity with no bus holding 349 | Wire.endTransmission(); 350 | 351 | //Hang out while measurement is taken. 50mS max, page 4 of datasheet. 352 | //delay(55); 353 | delay(95); 354 | //Read result 355 | Wire.requestFrom(HTDU21D_ADDRESS, 3); 356 | 357 | //Wait for data to become available 358 | int counter = 0; 359 | while(Wire.available() < 3) 360 | { 361 | counter++; 362 | delay(1); 363 | if(counter > 100) return 0; //Error out 364 | } 365 | 366 | msb = Wire.read(); 367 | lsb = Wire.read(); 368 | checksum = Wire.read(); 369 | 370 | unsigned int rawHumidity = ((unsigned int) msb << 8) | (unsigned int) lsb; 371 | rawHumidity &= 0xFFFC; //Zero out the status bits but keep them in place 372 | 373 | return(rawHumidity); 374 | } 375 | 376 | //Given the raw temperature data, calculate the actual temperature 377 | float calc_temp(int SigTemp) 378 | { 379 | float tempSigTemp = SigTemp / (float)65536; //2^16 = 65536 380 | float realTemperature = -46.85 + (175.72 * tempSigTemp); //From page 14 381 | 382 | return(realTemperature); 383 | } 384 | 385 | //Given the raw humidity data, calculate the actual relative humidity 386 | float calc_humidity(int SigRH) 387 | { 388 | float tempSigRH = SigRH / (float)65536; //2^16 = 65536 389 | float rh = -6 + (125 * tempSigRH); //From page 14 390 | 391 | return(rh); 392 | } 393 | 394 | //Read the user register 395 | byte read_user_register(void) 396 | { 397 | byte userRegister; 398 | 399 | //Request the user register 400 | Wire.beginTransmission(HTDU21D_ADDRESS); 401 | Wire.write(READ_USER_REG); //Read the user register 402 | Wire.endTransmission(); 403 | 404 | //Read result 405 | Wire.requestFrom(HTDU21D_ADDRESS, 1); 406 | 407 | userRegister = Wire.read(); 408 | 409 | return(userRegister); 410 | } 411 | 412 | //Write to the user register 413 | //NOTE: We disable all bits except for measurement resolution 414 | //Bit 7 & 0 = Measurement resolution 415 | //Bit 6 = Status of battery 416 | //Bit 5/4/3 = Reserved 417 | //Bit 2 = Enable on-board heater 418 | //Bit 1 = Disable OTP reload 419 | void write_user_register(byte thing_to_write) 420 | { 421 | byte userRegister = read_user_register(); //Go get the current register state 422 | userRegister &= 0b01111110; //Turn off the resolution bits 423 | thing_to_write &= 0b10000001; //Turn off all other bits but resolution bits 424 | userRegister |= thing_to_write; //Mask in the requested resolution bits 425 | 426 | //Request a write to user register 427 | Wire.beginTransmission(HTDU21D_ADDRESS); 428 | Wire.write(WRITE_USER_REG); //Write to the user register 429 | Wire.write(userRegister); //Write to the data 430 | Wire.endTransmission(); 431 | } 432 | 433 | //Give this function the 2 byte message (measurement) and the check_value byte from the HTU21D 434 | //If it returns 0, then the transmission was good 435 | //If it returns something other than 0, then the communication was corrupted 436 | //From: http://www.nongnu.org/avr-libc/user-manual/group__util__crc.html 437 | //POLYNOMIAL = 0x0131 = x^8 + x^5 + x^4 + 1 : http://en.wikipedia.org/wiki/Computation_of_cyclic_redundancy_checks 438 | #define SHIFTED_DIVISOR 0x988000 //This is the 0x0131 polynomial shifted to farthest left of three bytes 439 | 440 | unsigned int check_crc(uint16_t message_from_sensor, uint8_t check_value_from_sensor) 441 | { 442 | //Test cases from datasheet: 443 | //message = 0xDC, result is 0x79 444 | //message = 0x683A, result is 0x7C 445 | //message = 0x4E85, result is 0x6B 446 | 447 | uint32_t remainder = (uint32_t)message_from_sensor << 8; //Pad with 8 bits because we have to add in the result/check value 448 | remainder |= check_value_from_sensor; //Add on the check value 449 | 450 | uint32_t divsor = (uint32_t)SHIFTED_DIVISOR; 451 | 452 | for (int i = 0 ; i < 16 ; i++) //Operate on only 16 positions of max 24. The remaining 8 are our remainder and should be zero when we're done. 453 | { 454 | //Serial.print("remainder: "); 455 | //Serial.println(remainder, BIN); 456 | //Serial.print("divsor: "); 457 | //Serial.println(divsor, BIN); 458 | //Serial.println(); 459 | 460 | if( remainder & (uint32_t)1<<(23 - i) ) //Check if there is a one in the left position 461 | remainder ^= divsor; 462 | 463 | divsor >>= 1; //Rotate the divsor max 16 times so that we have 8 bits left of a remainder 464 | } 465 | 466 | return remainder; 467 | } 468 | 469 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESP8266-SHT21-HTU21-BMP180-DHT22-Thingspeak-logger 2 | 3 | Based on the https://github.com/squix78/esp8266-projects/tree/master/arduino-ide/thingspeak-data-logger 4 | 5 | ESP8266 / Wemos D1 mini with BMP180, SHT21 / HTU21 18650 Lipo, Lipo Charger with protection circuit and a BH1750 Sensor. 6 | The BH1750 is not visible in the video. 7 | 8 | Connection of a DHT22 as an low budget alternative to the SHT21/DHT21 is possible. 9 | 10 | To the lipo charger you can connect a 5V or 5.5V solar cell. 11 | 12 | Puts up the following values to thingspeak: 13 | 14 | - Temperature 15 | - Humidity 16 | - Lux 17 | - Humidex 18 | - Heatindex 19 | - Battery voltage of the node 20 | - Dewpoint 21 | - Pressure 22 | 23 | https://www.youtube.com/watch?v=g3ziCE5joGM 24 | 25 | Used parts: 26 | 27 | Lipo Charger: 28 | www.aliexpress.com/item/1Pc-High-Quality-5V-18650-Lithium-Battery-Charging-Board-Micro-USB-1A-Charger-Module-Drop-Shipping/32290456683.html 29 | 30 | Enclosure: 31 | www.aliexpress.com/store/product/3pcs-Free-shipping-plastic-box-for-custom-made-plastic-enclosure-for-electronic-project-abs-plastic/1352312_2040058036.html 32 | 33 | Wemos D1 (ESP8266) 34 | www.aliexpress.com/item/D1-mini-Mini-NodeMcu-4M-bytes-Lua-WIFI-Internet-of-Things-development-board-based-ESP8266/32529101036.html 35 | 36 | Pressure Sensor: 37 | www.aliexpress.com/item/1PCS-GY-68-BMP180-Replace-BMP085-Digital-Barometric-Pressure-Sensor-Module-For-Arduino/32346767511.html 38 | 39 | Lux Sensor 40 | www.aliexpress.com/item/GY-302-BH1750-BH1750FVI-light-intensity-illumination-module-for-arduino-3V-5V/32341898423.html 41 | 42 | Temp/Humidity Sensor HTU21: 43 | http://www.ebay.com/itm/181962636668 44 | 45 | or 46 | 47 | Temp/Humidity Sensor SHT21: 48 | http://www.ebay.com/itm/New-SHT21-Digital-Humidity-And-Temperature-Sensor-Module-Replace-SHT11-SHT15-/131156012885 49 | 50 | DC StepUp Module: 51 | http://www.ebay.com/itm/111851597705 52 | 53 | Battery: 54 | http://www.ebay.com/itm/Hot-3-7V-6000mAh-18650-Li-ion-Rechargeable-Battery-for-Flashlight-/291618980078 55 | 56 | Battery holder: 57 | http://www.ebay.com/itm/New-Hot-5Pcs-Battery-Case-Box-Holder-for-18650-Li-ion-Batteries-Cell-3-7V-/252091236855 58 | 59 | Resistor: 60 | 110k 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /logger_picture_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piwrks/ESP8266-SHT21-HTU21-BMP180-DHT22-Thingspeak-logger/6e71ea321819bd22704bceff79cf7560779fa63c/logger_picture_1.jpg --------------------------------------------------------------------------------