Humidity Recorder control with Android App
A Humidity Recorder made with Arduino, control and display data with Android App, both Android and Arduino project are very stable.
Components and supplies
1
SHT31
1
HC-05 Bluetooth Module
1
Arduino Nano R3
1
7 Segment LED Display, InfoVue
1
DS3231MPMB1 Peripheral Module
Apps and platforms
1
Controller of Arduino humidity recorder
Project description
Code
Humidity Recoder
arduino
I write the code by Arduino IDE, you may choice your own editor and paste the code.
1 2#include <Arduino.h> 3#include <EEPROM.h> 4#include <TM1637.h> 5#include <Wire.h> 6#include <Adafruit_SHT31.h> 7#include <DS3231.h> 8#include <ZEeprom.h> 9#include <SoftwareSerial.h> 10#include <Streaming.h> 11#include <avr/sleep.h> 12#include <LowPower.h> 13 14//byte runtime[4] = {0, 0, 0, 0}; 15#define RT_BT 1; 16#define RT_SYS 0; 17 18// Runtime bluetooth 19#define IsConnected 0 20//#define IsVerified 1 21 22// Settings address in ROM 23#define ADDR_BRIGHTNESS 1023 24#define ADDR_REC_INTERVAL 1022 25 26#define RTC_ADDRESS 0x68 27#define CLOCK_INT_PIN 2 28#define YEAR 5 29#define MON 4 30#define DATE 3 31#define HOUR 2 32#define MIN 1 33#define SEC 0 34DS3231 rtc; 35RTClib rtcLib; // For get now(); 36uint8_t sysClock[6] = {0, 0, 0, 0, 0, 0}; 37volatile bool clockIntr = false, bluetoothIntr = false; 38uint32_t upTimer = 0; 39 40#define CLOCK_WAKEUP 1 41#define WDT_WAKEUP 2 42byte wakeupPhase = 0; 43unsigned long clockSecMillis = 0; 44 45#define EEPROM_ADDRESS 0x57 46ZEeprom * extRom; 47unsigned int extRomSize = 4096; 48 49uint8_t innerRomStartAddr = 0x00; 50uint16_t innerRomEndAddr = 999; 51 52#define CLK A1 //Pins for TM1637 53#define DIO A0 54TM1637 tm1637(CLK, DIO); 55int clockLedBright = BRIGHT_TYPICAL; 56 57#define DHT31_ADDRESS 0x44 58Adafruit_SHT31 sht31 = Adafruit_SHT31(); 59bool isRecHumdt = true; 60bool isRecTemp = false; 61uint8_t recInterval = 1; // minute. 62struct RecordSet { 63 uint32_t lastRecTime; 64 uint16_t lastRecAddr; 65} ThRec; 66 67#define BLUETOOTH_STATE_PIN 3 68bool isBluetoothConnected = false; 69//SoftwareSerial BTserial(4, 5); 70SoftwareSerial BTserial(17, 16); 71 72#define DUMP 1 73#define SET_TIME 2 74#define GET_STAT 3 75long dumpIndex = -1; 76byte data[32]; 77 78#define READY 0 79#define BUSY 1 80#define ERR 2 81 82#define NO_RTC 1 83#define NO_EEPROM 2 84#define NO_DHT31 3 85 86class Led { 87 byte ledPin = LED_BUILTIN; 88 byte sysState = READY; 89 unsigned long ledPrevMillis = 0; 90 bool hasErr=false; // hasErr is hightest priority flag, if it is true, skip sysState flag. 91 92 public: 93 Led() {} 94 Led(int pin) { 95 ledPin = pin; 96 } 97 98 void setup() { 99 pinMode(ledPin, OUTPUT); 100 } 101 setState(int state) { 102 sysState = state; 103 } 104 int getState() { 105 return sysState; 106 } 107 108 void loop() { 109 if(hasErr) // If hasErr is true, skip sysState flag. 110 ledErr(); 111 else if (sysState == READY) 112 ledReady(); 113 } 114 115 void busy(){ 116 digitalWrite(ledPin, HIGH ); 117 sysState = BUSY; 118 } 119 void unBusy(){ 120 digitalWrite(ledPin, LOW ); 121 sysState = READY; 122 } 123 124 void hasError(bool isErr){ 125 hasErr=isErr; 126 } 127 128 void loopErrSignal(int num){ 129 while(true){ 130 for(int i=0;i<num;i++){ 131 digitalWrite(ledPin, HIGH ); 132 delay(100); 133 digitalWrite(ledPin, LOW ); 134 delay(300); 135 } 136 delay(1000); 137 } 138 } 139 140 private: 141 142 void ledReady() { 143 if (sysClock[SEC] % 3 == 0) { 144 if(wakeupPhase == WDT_WAKEUP) 145 digitalWrite(ledPin, LOW ); 146 else 147 digitalWrite(ledPin, HIGH ); 148 } 149 } 150 151 void ledErr() { 152 if(wakeupPhase == WDT_WAKEUP) 153 digitalWrite(ledPin, LOW ); 154 else 155 digitalWrite(ledPin, HIGH ); 156 } 157}; 158 159Led led; 160 161void setup() { 162 Serial.begin(57600); 163 Wire.setClock(400000); 164 Wire.begin(); 165 166 if (isDevExist(RTC_ADDRESS)) 167 Serial.println("FOUND RTC!"); 168 else { 169 Serial.println("RTC NOT found!"); 170 led.loopErrSignal(NO_RTC); 171 } 172 173 // Check is EEPROM exist or not. 174 if (isDevExist(EEPROM_ADDRESS)) 175 Serial.println("FOUND Eeprom!"); 176 else { 177 Serial.println("Eeprom NOT found!"); 178 led.loopErrSignal(NO_EEPROM); 179 } 180 181 if (sht31.begin(DHT31_ADDRESS))// Set to 0x45 for alternate i2c addr 182 Serial.println("FOUND SHT31!"); 183 else { 184 Serial.println("Couldn't find SHT31."); 185 led.loopErrSignal(NO_DHT31); 186 } 187 188 extRom = new ZEeprom(); 189 extRom->begin(Wire, EEPROM_ADDRESS, AT24C32); 190 191 rtc.setClockMode(false); 192 syncRTC(); 193 Serial << "Get RTC time: " << sysClock[YEAR] << ", " << sysClock[MON] << ", " << sysClock[DATE] << ", " << sysClock[HOUR] << ", " << sysClock[MIN] << ", " << sysClock[SEC] << ", " << endl; 194 rtc.enableOscillator(true, false, 0); // Turn on 195 rtc.enable32kHz(true); 196 pinMode(CLOCK_INT_PIN, INPUT_PULLUP); 197 attachInterrupt(0, clockIsr, FALLING); //assign int0 198 199 BTserial.begin(38400); 200 attachInterrupt(1, bluetoothIsr, CHANGE); //assign int0 201 202 recInterval = EEPROM.read(ADDR_REC_INTERVAL); 203 if (recInterval == 0xFF) recInterval = 1; 204 ThRec.lastRecTime = 0; 205 ThRec.lastRecAddr = 0; 206 207 tm1637.init(); 208 int bright = EEPROM.read(ADDR_BRIGHTNESS); 209 if (bright < 8) { 210 Serial.print("Get bright from option ROM: "); 211 Serial.println(bright); 212 clockLedBright = bright; 213 tm1637.set(bright); 214 } 215 else tm1637.set(clockLedBright); 216 showClockLed(); 217 218} 219 220void clockIsr() { 221 clockIntr = true; 222 //Serial.println("Clock interrupt!"); 223} 224 225void bluetoothIsr() { 226 bluetoothIntr = true; 227 //Serial.println("Bluetooth interrupt!"); 228} 229 230void loop() { 231 //Serial.print("Program alive: "); 232 if (clockIntr) maintainClock(); 233 if (bluetoothIntr) { 234 byte pin = digitalRead(BLUETOOTH_STATE_PIN); 235 if (pin == HIGH) { 236 isBluetoothConnected = true; 237 //Serial.println("Bluetooth Connected(state HIGH)."); 238 } 239 else { 240 isBluetoothConnected = false; 241 //Serial.println("Bluetooth Disconnected(state LOW)."); 242 } 243 bluetoothIntr = false; 244 } 245 246 led.loop(); 247 showClockLed(); 248 249 if (sysClock[SEC] == 0) { 250 // Avoid record many times in one second. 251 if (getUnixtimeFromSysClock() >= ThRec.lastRecTime + (recInterval * 10)) { 252 recHumidity(); 253 } 254 } 255 256 checkBtCmd(); 257 258 if (!isBluetoothConnected) { 259 if (wakeupPhase == CLOCK_WAKEUP) { 260 //Serial.println("Sleep 500 ms."); 261 LowPower.powerDown(SLEEP_500MS, ADC_OFF, BOD_OFF); 262 wakeupPhase = WDT_WAKEUP; 263 } 264 else { 265 //Serial.println("Sleep Forever"); 266 LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); 267 } 268 } 269 270} 271 272void maintainClock() { 273 clockIntr = false; 274 upTimer++; 275 wakeupPhase = CLOCK_WAKEUP; 276 clockSecMillis = millis(); 277 278 //Serial << "Clock Sec Millis = " << clockSecMillis << endl; 279 280 sysClock[SEC]++; 281 if (sysClock[SEC] < 60) 282 return; 283 284 sysClock[SEC] = 0; 285 sysClock[MIN]++; 286 287 if (sysClock[MIN] < 60) 288 return; 289 290 sysClock[MIN] = 0; 291 sysClock[HOUR]++; 292 293 if (sysClock[HOUR] == 24) 294 syncRTC(); 295 296 //Serial.print("Got a interrupt from clock at "); 297 //Serial.println(millis()); 298} 299 300void recHumidity() { 301 float t = sht31.readTemperature(); 302 float h = sht31.readHumidity(); 303 304 if (! isnan(t)) { // check if 'is not a number' 305 //Serial.print("Temp *C = "); Serial.println(t); 306 t += 0.5; 307 } else { 308 //Serial.println("Failed to read temperature"); 309 t = -1; 310 } 311 312 if (! isnan(h)) { // check if 'is not a number' 313 //Serial.print("Hum. % = "); Serial.println(h); 314 h += 0.5; 315 } else { 316 //Serial.println("Failed to read humidity"); 317 h = -1; 318 } 319 //Serial.println(); 320 321 byte bt = (byte)t; 322 byte bh = (byte)h; 323 uint16_t innerRomSize = innerRomEndAddr - innerRomStartAddr + 1; 324 byte dataLen = (isRecTemp) ? 2 : 1; 325 326 //Serial << "Save data T: " << bt << ", H: " << bh << " to Addr "; 327 if (ThRec.lastRecTime == 0 || ThRec.lastRecAddr + dataLen >= extRomSize + innerRomSize) { // if lastRecTime == 0 mean it is first time to record data. 328 ThRec.lastRecAddr = 0; 329 //Serial << ThRec.lastRecAddr << "(External ROM)" << endl; 330 if (isRecHumdt)writeRom(ThRec.lastRecAddr, &bh, 0, 1); 331 if (isRecTemp)writeRom(ThRec.lastRecAddr + 1, &bt, 0, 1); 332 } else if (ThRec.lastRecAddr + dataLen >= extRomSize) { 333 334 // Write in inner ROM 335 ThRec.lastRecAddr += dataLen; 336 int innerAddr = ThRec.lastRecAddr - extRomSize + innerRomStartAddr; 337 //Serial << ThRec.lastRecAddr << "(Inner: " << innerAddr << ")" << endl; 338 if (isRecHumdt)EEPROM.write(innerAddr, bh); 339 if (isRecTemp)EEPROM.write(innerAddr + 1, bt); 340 } else { 341 // Write in external ROM 342 ThRec.lastRecAddr += dataLen; 343 //Serial << ThRec.lastRecAddr << "(External ROM)" << endl; 344 if (isRecHumdt)writeRom(ThRec.lastRecAddr + 1, &bh, 0, 1); 345 if (isRecTemp) writeRom(ThRec.lastRecAddr, &bt, 0, 1); 346 } 347 //DateTime dt = rtcLib.now(); 348 //ThRec.lastRecTime=dt.unixtime(); 349 ThRec.lastRecTime = getUnixtimeFromSysClock(); 350 //Serial << "Time: " << ThRec.lastRecTime <<endl; 351} 352 353uint32_t getUnixtimeFromSysClock() { 354 uint32_t t; 355 uint16_t days = date2days(sysClock[YEAR], sysClock[MON], sysClock[DATE]); 356 t = time2long(days, sysClock[HOUR], sysClock[MIN], sysClock[SEC]); 357 //t += 946684800; //SECONDS_FROM_1970_TO_2000 358 359 return t; 360} 361static const uint8_t daysInMonth [] PROGMEM = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 362static uint16_t date2days(uint16_t y, uint8_t m, uint8_t d) { 363 if (y >= 2000) 364 y -= 2000; 365 uint16_t days = d; 366 for (uint8_t i = 1; i < m; ++i) 367 days += pgm_read_byte(daysInMonth + i - 1); 368 if (m > 2 && y % 4 == 0) 369 ++days; 370 return days + 365 * y + (y + 3) / 4 - 1; 371} 372 373static long time2long(uint16_t days, uint8_t h, uint8_t m, uint8_t s) { 374 return ((days * 24L + h) * 60 + m) * 60 + s; 375} 376 377void syncRTC() { 378 379 DateTime dt = rtcLib.now(); 380 381 sysClock[YEAR] = dt.year() - 2000; 382 sysClock[MON] = dt.month(); 383 sysClock[DATE] = dt.day(); 384 sysClock[HOUR] = dt.hour(); 385 sysClock[MIN] = dt.minute(); 386 sysClock[SEC] = dt.second(); 387 //Serial << "RTC Unixtime: " << dt.unixtime() <<", sysClock Unixtime: " << getUnixtimeFromSysClock() << endl; 388} 389 390void checkBtCmd() { 391 if ( ! BTserial.available() || led.getState() == BUSY)return; 392 393 char c = BTserial.read(); 394 uint32_t startTime=millis(); 395 396 //Serial.print("Receive command from Bluetooth: "); 397 //Serial << c << "(0x" ; 398 //Serial.print(c , HEX); 399 //Serial.println(')'); 400 401 if (c == 'S') { 402 bool battery = rtc.oscillatorCheck(); 403 int temp = (int)(sht31.readTemperature() + 0.5); 404 int hmd = (int)(sht31.readHumidity() + 0.5); 405 406 //Serial << "Write uptimer: " << upTimer << endl; 407 BTserial.write(upTimer >> 24); 408 BTserial.write(upTimer >> 16); 409 BTserial.write(upTimer >> 8); 410 BTserial.write(upTimer); 411 BTserial.write(battery); 412 BTserial.write(recInterval); 413 BTserial.write(ThRec.lastRecAddr >> 8); 414 BTserial.write(ThRec.lastRecAddr); 415 BTserial.write(temp); 416 BTserial.write(hmd); 417 } 418 419 else if (c == 'D') { 420// Data format: dataLen(2byte), recInterval(byte), isIncludeTemp(byte), lastRecAddr(2byte), lastRecTime(4byte), data ... 421 422 uint16_t dataLength = extRomSize + innerRomEndAddr - innerRomStartAddr + 1 + 8; // 8 is meta data length. 423 byte isIncludeTemp = ((isRecTemp) ? (byte)1 : (byte)0); 424 BTserial.write(dataLength >> 8); 425 BTserial.write(dataLength); 426 BTserial.write(recInterval); 427 BTserial.write(isIncludeTemp); 428 BTserial.write(ThRec.lastRecAddr >> 8); 429 BTserial.write(ThRec.lastRecAddr); 430 BTserial.write(ThRec.lastRecTime >> 24); 431 BTserial.write(ThRec.lastRecTime >> 16); 432 BTserial.write(ThRec.lastRecTime >> 8); 433 BTserial.write(ThRec.lastRecTime); 434 435 //Serial << "Record Interval: " << recInterval << endl; 436 //Serial << "Last Record Index: " << ThRec.lastRecAddr << endl; 437 //Serial << "Last record time: " << ThRec.lastRecTime << endl; 438 led.busy(); 439 //Serial.println("Dump data from external ROM ..."); 440 dumpExtRom(); 441 dumpInnerRom(); 442 //Serial.println("Dump Finish."); 443 led.unBusy(); 444 } 445 else if (c == 'T') { 446 // If Command is set time, then set clock time immediately no matter how system busy. 447 448 int recv[6]; 449 for (int i = 0; i < 6; i++) { 450 while(!BTserial.available()){ 451 if(millis()-startTime>=4000)return; // If it no data come over 4 second, skip command. 452 } 453 recv[i] = BTserial.read(); 454 } 455 setClock(recv[0], recv[1], recv[2], recv[3], recv[4], recv[5]); 456 } 457 else if ( c == 'I') { 458 // For setting humidity record interval. 459 460 while(!BTserial.available()){ 461 if(millis()-startTime>=4000)return; // If it no data come over 4 second, skip command. 462 } 463 int interval = BTserial.read(); 464 //Serial.print("Get set record interval command: "); Serial.println(interval); 465 466 recInterval = interval; 467 EEPROM.write(ADDR_REC_INTERVAL, interval); 468 ThRec.lastRecAddr = 0; 469 } 470 471 else if ( c == 'B') { 472 // For setting brightness of 4 digital time LED. 473 474 while(!BTserial.available()){ 475 if(millis()-startTime>=4000)return; // If it no data come over 4 second, skip command. 476 } 477 int b = BTserial.read(); 478 //Serial.print("Get brightness command: "); 479 //Serial.println(b, DEC); 480 if (b < 8) { // B指令後接收的資料必需<7,最後送出0xFF結束命令。 481 //Serial.println("Set value to Clock LED."); 482 clockLedBright = b; 483 tm1637.set(b); 484 } 485 486 else if (b == 127) { // 當送出0x127後將數值存起來 487 //Serial.println("Get FINAL brightness command, save value to ROM."); 488 int bright = EEPROM.read(ADDR_BRIGHTNESS); 489 if (bright == clockLedBright)Serial.println("The value same as value in ROM, skip save."); 490 if (bright != clockLedBright) { 491 //Serial.print("Write new bright value to ROM: "); 492 //Serial.println(clockLedBright); 493 EEPROM.write(ADDR_BRIGHTNESS, clockLedBright); 494 } 495 } 496 497 } 498} 499 500void showClockLed() { 501 502 if (!isBluetoothConnected && (wakeupPhase == CLOCK_WAKEUP) && (tm1637._PointFlag == POINT_OFF) 503 || isBluetoothConnected && (millis() - clockSecMillis < 500) && (tm1637._PointFlag == POINT_OFF) 504 ) { 505 //Serial.println("Set number of clock LED."); 506 //Serial.println("Colon ON"); 507 tm1637.point(true); 508 tm1637.display(0, sysClock[HOUR] / 10); // hour 509 tm1637.display(1, sysClock[HOUR] % 10); 510 tm1637.display(2, sysClock[MIN] / 10); // minutes 511 tm1637.display(3, sysClock[MIN] % 10); // 512 } 513 514 515 if (!isBluetoothConnected && (wakeupPhase == WDT_WAKEUP) && (tm1637._PointFlag == POINT_ON) 516 || isBluetoothConnected && (millis() - clockSecMillis > 500) && (tm1637._PointFlag == POINT_ON) 517 ) { 518 //Serial.println("Turn off colon of clock LED."); 519 //Serial.println("Colon OFF"); 520 tm1637.point(false); 521 tm1637.display(0, sysClock[HOUR] / 10); // hour 522 tm1637.display(1, sysClock[HOUR] % 10); 523 tm1637.display(2, sysClock[MIN] / 10); // minutes 524 tm1637.display(3, sysClock[MIN] % 10); // 525 } 526 527} 528 529// Set time to RTC DS3231 530void setClock(byte year, byte mon, byte dayOfMonth, byte hour, byte min, byte sec) { 531 unsigned long startTime = millis(); 532 533 uint16_t y = (uint16_t)year; 534 //Serial << "y = " << y << endl; 535 rtc.setYear(y); // use the time_t value to ensure correct weekday is set 536 rtc.setMonth(mon); 537 rtc.setDate(dayOfMonth); 538 rtc.setHour(hour); 539 rtc.setMinute(min); 540 rtc.setSecond(sec); 541 542 unsigned long spendTime = millis() - startTime; 543 544 //Serial.print("RTC set to: "); 545 //Serial << y <<":" <<mon <<":"<<dayOfMonth<<"_"<<hour<<":"<<min<<":"<<sec<<endl; 546 //Serial << " spend " << spendTime << "ms." << endl; 547 548 syncRTC(); 549 //rtc.adjust(DateTime(year, mon, dayOfMonth, hour, min, sec)); 550} 551 552bool isDevExist(int addr) { 553 Wire.beginTransmission(addr); 554 int result = Wire.endTransmission(); 555 return (result == 0); 556} 557 558void accessEeprom() { 559 const byte address = 31; 560 //Serial.println("Read byte from EEPROM memory before write..."); 561 byte data = extRom->readByte(address); 562 563 delay(10); 564 extRom->writeByte(address, ((data == 0xFF) ? 0xAA : 0xFF)); 565 566 delay(10); 567 data = extRom->readByte(address); 568} 569 570void dumpExtRom() { 571 int c = 0; 572 for (unsigned int addr = 0; addr < extRomSize; addr += 32) { 573 //Serial.print("Read address "); 574 //Serial.println(addr); 575 576 //extRom->readBytes(addr, 32, data); 577 readRom(addr, data, 0, 32); 578 579 loop(); 580 581 // Write to BTserial. 582 if (led.getState() == READY) return; // Abord command. 583 BTserial.write(data, 32); 584 loop(); 585 //} 586 } 587 BTserial.flush(); 588} 589 590void dumpInnerRom() { 591 int addr = 0; 592 for (int i = 0; i < 40; i++) { 593 for (int j = 0; j < 25; j++) { 594 data[j] = EEPROM.read(addr++); 595 } 596 loop(); 597 BTserial.write(data, 25); 598 loop(); 599 } 600 BTserial.flush(); 601} 602 603void writeRom(unsigned int address, byte * data, int offset, int n) { 604 Wire.beginTransmission(EEPROM_ADDRESS); 605 //if (Wire.endTransmission()==0) { 606 Wire.beginTransmission(EEPROM_ADDRESS); 607 Wire.write(address >> 8); 608 Wire.write(address & 0xFF); 609 byte *adr = data + offset; 610 Wire.write(adr, n); 611 Wire.endTransmission(); 612 delay(10); 613} 614 615// Read less then 32byte everytime. 616void readRom(unsigned int address, byte * data, int offset, int n) { 617 //unsigned int dataAddr=address & (uint32_t)0x00000fff; 618 Wire.beginTransmission(EEPROM_ADDRESS); 619 if (Wire.endTransmission() == 0) { 620 Wire.beginTransmission(EEPROM_ADDRESS); 621 Wire.write(address >> 8); 622 Wire.write(address & 0xFF); 623 if (Wire.endTransmission() == 0) { 624 int r = 0; 625 Wire.requestFrom(EEPROM_ADDRESS, n); 626 while (Wire.available() > 0 && r < n) { 627 data[offset + r] = (byte)Wire.read(); 628 r++; 629 } 630 } 631 } 632 else { 633 //Serial.print("I2C bus not ready while readRom()!!!"); 634 led.loopErrSignal(NO_EEPROM); 635 } 636} 637
Downloadable files
humidityrecoderatmega328pu_OVA8Z8Ol25.fzz
humidityrecoderatmega328pu_OVA8Z8Ol25.fzz
humidityrecoder_eWBFkJkf5I.fzz
humidityrecoder_eWBFkJkf5I.fzz
humidityrecoderatmega328pu_OVA8Z8Ol25.fzz
humidityrecoderatmega328pu_OVA8Z8Ol25.fzz
humidityrecoder_eWBFkJkf5I.fzz
humidityrecoder_eWBFkJkf5I.fzz
Comments
Only logged in users can leave comments