Components and supplies
Arduino Nano 33 IoT
1.3" IIC I2C Serial 128x64 SSH1106 OLED LCD Display
SPI SD card module
CC2650STK SensorTag Kit
Arduino MKR WiFi 1010
Tools and machines
Servo Motor, Premium Male/Male Jumper Wires
Breadboard, 830 Tie Points
Project description
Code
YADL_V1_0R
arduino
Complete program code for the data logger
1//********************************************************************************* 2// YADL SensorTag Data Logger v1.0R [DrG] 3// ** This software is offered strictly as is with no guarantees or warranties. ** 4// ** - USE IT AT YOUR OWN RISK! ** 5//********************************************************************************* 6// 7// Uses: 8// WiFiNINA v1.40 9// RTCZero 1.6.0 10// ArduinoBLE v1.1.1 11// SD v1.2.3 12// U8g2 (U8x8) v2.26.14 13// 14// Arduino IDE v1.8.10 15// 16// Hardware: 17// MKR1010 / NANO 33 IOT (both have been tested) 18// microSD card (both generics and MicroElectronika click board tested) 19// HiLetgo 1.3" I2C monochrome OLED (others should work with modification) 20// 21// Note: Replace the code entries below with your network info: 22// char ssid[] = "XXXXXXXXXX"; 23// char pass[] = "XXXXXXXXXX"; 24// 25// Note: set GMT (with DST if needed) in code entry: 26// const int GMT =XX 27// 28// #includes 29#include <WiFiNINA.h> 30#include <RTCZero.h> 31#include <ArduinoBLE.h> 32#include <SPI.h> 33#include <SD.h> 34#include <U8x8lib.h> 35#include <avr/dtostrf.h> // needed for MKR1010 36 37//#define DEBUG // uncomment this line for serial monitor output 38 39RTCZero rtc; 40BLEDevice peripheral; 41File SDF; 42 43U8X8_SH1106_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE); 44 45// Global structure to hold the sensor data 46struct DATA { 47 float tem; // HDC1000 temperature F 48 float hum; // HDC1000 relative humidity %RH 49 float bptemp; // BMP 280 die temperature F 50 float bp; // BMP 280 barometric pressure in hectoPascals (1 hPa = 100 Pa) 51 float li; // OPT3001 lux 52 float temd; // TMP007 die temperature F 53 float temo; // TMP007 object temperature F 54}; 55 56typedef struct DATA DATA; 57DATA SensorData; 58 59// for SensorTag sensors 60uint8_t sensorOn = 1; 61uint8_t sensorOff = 0; 62 63// lcd vars 64char degree[] = {0xb0, 0x00}; 65char percent[] = {0x25, 0x00}; 66char p_buffer[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 67 68// clock change catcher 69int lastmin; 70 71// for RTC 72unsigned long epoch; 73int numberOfTries = 0, maxTries = 6; 74 75int status = WL_IDLE_STATUS; // WiFiNINA use 76 77// Common user-changeable switches 78const int GMT = -2; //change this to adapt it to your time zone 79byte SDswitch = 1; // SDswitch 1=ON (write to SD) or 0 (Do not write to SD) 80char fname[] = "STDATA.txt"; // data log file Name 81 82//period defines the length of time between measurements in milliseconds 83// note that this does not includes delays for sensor reads (~8.7 sec) 84long period = 600000L; // 10 minutes 85//long period = 5000L; // 5 sec for testing 86 87char ssid[] = ""; // your network SSID (name) 88char pass[] = ""; // your network password (use for WPA, or use as key for WEP) 89int keyIndex = 0; // your network key Index number (needed only for WEP) 90 91// SensorTag characteristic definitions 92// BMP280 93BLECharacteristic BPConCharacteristic; 94BLECharacteristic BPValCharacteristic; 95// OPT3001 96BLECharacteristic OPTConCharacteristic; 97BLECharacteristic OPTValCharacteristic; 98// TMP007 99BLECharacteristic IRTConCharacteristic; 100BLECharacteristic IRTValCharacteristic; 101// HDC1000 102BLECharacteristic HUMConCharacteristic; 103BLECharacteristic HUMValCharacteristic; 104//------------------------------------------------------------------ 105 106void setup() { 107 u8x8.begin(); // start lcd driver, will clear display 108 u8x8.setFont(u8x8_font_amstrad_cpc_extended_f); // 8 X 8 font 109 u8x8.drawString(0, 0, "YADL starting..."); 110#ifdef DEBUG 111 Serial.begin(9600); 112 delay(5000); // delay for user to open the serial monitor 113 Serial.println("YADL MKR1010/NANO IOT 33 SensorTag Data Logger"); 114 Serial.println(); 115#endif 116 // check the SD card 117 if (SDswitch == 1) { 118 if (!SD.begin(4)) { 119 u8x8.drawString(0, 2 , "No SD card!"); 120 u8x8.drawString(0, 3 , "Terminal Error!"); 121#ifdef DEBUG 122 Serial.println("SD Card initialization failed!"); 123#endif 124 while (1); 125 } 126 else { 127 u8x8.drawString(0, 2 , "SD card found. "); 128 delay(2000); // to let user know 129 u8x8.drawString(0, 2 , " "); 130#ifdef DEBUG 131 Serial.println("SD Card found"); 132#endif 133 } 134 } 135 else { 136 u8x8.drawString(0, 2 , "No SD card"); 137 u8x8.drawString(0, 3 , "option"); 138 delay(2000); // to let user know 139 u8x8.drawString(0, 2 , " "); 140 u8x8.drawString(0, 3 , " "); 141#ifdef DEBUG 142 Serial.println("No SD Card option"); 143#endif 144 } 145 delay(2000); // to let user know about sd card 146 // check if the WiFi module works 147 if (WiFi.status() == WL_NO_SHIELD) { 148#ifdef DEBUG 149 Serial.println("WiFi shield not present"); 150#endif 151 u8x8.drawString(0, 1 , "NO WiFi!"); 152 u8x8.drawString(0, 2 , "Terminal Error!"); 153 // don't continue: 154 while (true); 155 } 156 157 // attempt to connect to WiFi network: 158 u8x8.drawString(0, 2 , "Connecting....."); 159 while ( status != WL_CONNECTED) { 160#ifdef DEBUG 161 Serial.print("Attempting to connect to SSID: "); 162 Serial.println(ssid); 163#endif 164 // Connect to WPA/WPA2 network. Change this line if using open or WEP network: 165 status = WiFi.begin(ssid, pass); 166 delay(10000); // wait 10 seconds for connection: 167 } 168 u8x8.drawString(0, 3 , "Connected! "); 169#ifdef DEBUG 170 printWiFiStatus(); // you're connected now, so print out the status: 171#endif 172 rtc.begin(); 173 do { 174 epoch = WiFi.getTime(); 175 numberOfTries++; 176 } 177 while ((epoch == 0) && (numberOfTries < maxTries)); 178 179 if (numberOfTries == maxTries) { 180 u8x8.drawString(0, 4 , "NTP Unreachable"); 181 u8x8.drawString(0, 5 , "TERMINAL ERROR!"); 182#ifdef DEBUG 183 Serial.print("NTP unreachable!!"); 184#endif 185 while (1); 186 } 187 else { 188 u8x8.drawString(0, 4 , "Got NTP Epoch "); 189 epoch = epoch + (GMT * 3600UL); // adjust offset for TZ/DST 190 rtc.setEpoch(epoch); 191#ifdef DEBUG 192 Serial.print("Epoch received: "); 193 Serial.print(epoch); 194 Serial.print(" "); 195 printP02D(rtc.getHours()); 196 Serial.print(":"); 197 printP02D(rtc.getMinutes()); 198 Serial.print(":"); 199 printP02D(rtc.getSeconds()); 200 Serial.print(" "); 201 Serial.print(rtc.getDay()); 202 Serial.print("/"); 203 Serial.print(rtc.getMonth()); 204 Serial.print("/"); 205 Serial.print(rtc.getYear()); 206 Serial.println(); 207#endif 208 WiFi.end(); 209 delay(15000); 210 u8x8.drawString(0, 5 , "WiFi Ended "); 211 u8x8.drawString(0, 6 , "Starting BLE "); 212 delay(2000); // to see it on the screen 213#ifdef DEBUG 214 Serial.println("WiFi.end executed"); 215#endif 216 } 217 // Try to initialize BLE 218 if (!BLE.begin()) { 219 Serial.println("Terminal Error: Could not start BLE!"); 220 u8x8.clear(); 221 u8x8.drawString(0, 0 , "BLE Start Fail"); 222 u8x8.drawString(0, 1 , "Terminal Error!"); 223 while (1); 224 } 225 BLE.scan(); 226 u8x8.clear(); 227 u8x8.drawString(0, 0 , "Scanning......"); 228} 229//------------------------------------------------------------------ 230void loop() { 231 long lastMillis = 0; // for period test 232 long nowMillis = 0; // for period test 233 234 // check if a peripheral has been discovered 235 peripheral = BLE.available(); 236 if (peripheral) { 237 // discovered a peripheral, print out address and local name 238#ifdef DEBUG 239 Serial.print("Found "); 240 Serial.print(peripheral.address()); 241 Serial.print(" '"); 242 Serial.print(peripheral.localName()); 243 Serial.println("' "); 244#endif 245 if (peripheral.localName() == "CC2650 SensorTag") { 246 BLE.stopScan(); // stop scanning 247 // connect to the peripheral 248 u8x8.drawString(0, 1 , "Connecting...."); 249#ifdef DEBUG 250 Serial.print("Connecting to SensorTag ..."); 251#endif 252 if (peripheral.connect()) { 253 u8x8.drawString(0, 2 , "Connected....."); 254#ifdef DEBUG 255 Serial.println("Connected..."); 256#endif 257 do_discovery(peripheral); 258 // Note: we do not subscribe to any services because we are not using notify 259 u8x8.clear(); 260 print_screenT(); 261#ifdef DEBUG 262 Serial.println("Reading sensors..."); 263 Serial.println(); 264#endif 265 } 266 else { 267 u8x8.drawString(0, 2 , "Scanning......"); 268#ifdef DEBUG 269 Serial.println(" scanning"); 270#endif 271 } 272 } 273 // main while connected loop 274 while (peripheral.connected()) { 275 read_BP(peripheral); 276 read_OPT(peripheral); 277 read_IRT(peripheral); 278 read_HUM(peripheral); 279 if (SDswitch) write_SDdata(); // write data to sd card 280 // screen for debug no print here as well 281#ifdef DEBUG 282 print_data(); 283#endif 284 print_screenValues(); 285 printclockD(1); // Update sensor clock 286 printclockD(2); // update current clock 287 lastmin = rtc.getMinutes(); 288 lastMillis = millis(); 289 // stay here until the period is up 290 // update current time here 291 while ( ( (nowMillis = millis()) - lastMillis) <= period) { 292 // need to update the clock here 293 if (lastmin != rtc.getMinutes()) { 294 lastmin = rtc.getMinutes(); 295 printclockD(2); // update current clock 296 } 297 } 298 } 299 // peripheral disconnected, start scanning again 300 u8x8.clear(); 301 u8x8.drawString(0, 2 , "Scanning......"); 302#ifdef DEBUG 303 Serial.println(" - rescan..."); 304#endif 305 BLE.scan(); 306 } 307} 308//------------------------------------------------------------------ 309 310// BLE SensorTag routines 311void do_discovery(BLEDevice peripheral) { 312 // discover the peripheral's attributes that we want 313 // barometric 314#ifdef DEBUG 315 Serial.print("Discovering attributes for Barometric Pressure service ..."); 316#endif 317 if (peripheral.discoverService("f000aa40-0451-4000-b000-000000000000")) { 318#ifdef DEBUG 319 Serial.println("discovered"); 320#endif 321 BPConCharacteristic = peripheral.characteristic("f000aa42-0451-4000-b000-000000000000"); 322 BPValCharacteristic = peripheral.characteristic("f000aa41-0451-4000-b000-000000000000"); 323 } 324 else { 325#ifdef DEBUG 326 Serial.println("ERROR: Barometric Pressure service discovery failed."); 327#endif 328 peripheral.disconnect(); 329 return; 330 } 331 // discover the peripheral's attributes that we want 332 // optical sensor 333#ifdef DEBUG 334 Serial.print("Discovering attributes for Luxometer service ..."); 335#endif 336 if (peripheral.discoverService("f000aa70-0451-4000-b000-000000000000")) { 337#ifdef DEBUG 338 Serial.println("discovered"); 339#endif 340 OPTConCharacteristic = peripheral.characteristic("f000aa72-0451-4000-b000-000000000000"); 341 OPTValCharacteristic = peripheral.characteristic("f000aa71-0451-4000-b000-000000000000"); 342 } 343 else { 344#ifdef DEBUG 345 Serial.println("Error: Luxometer service discovery failed."); 346#endif 347 peripheral.disconnect(); 348 return; 349 } 350 // IR 351#ifdef DEBUG 352 Serial.print("Discovering attributes for Infrared service ..."); 353#endif 354 if (peripheral.discoverService("f000aa00-0451-4000-b000-000000000000")) { 355#ifdef DEBUG 356 Serial.println("discovered"); 357#endif 358 IRTConCharacteristic = peripheral.characteristic("f000aa02-0451-4000-b000-000000000000"); 359 IRTValCharacteristic = peripheral.characteristic("f000aa01-0451-4000-b000-000000000000"); 360 } 361 else { 362#ifdef DEBUG 363 Serial.println("Error: Infrared service discovery failed."); 364#endif 365 peripheral.disconnect(); 366 return; 367 } 368 // humidity 369#ifdef DEBUG 370 Serial.print("Discovering attributes for Humidity service ..."); 371#endif 372 if (peripheral.discoverService("f000aa20-0451-4000-b000-000000000000")) { 373#ifdef DEBUG 374 Serial.println("discovered"); 375#endif 376 HUMConCharacteristic = peripheral.characteristic("f000aa22-0451-4000-b000-000000000000"); 377 HUMValCharacteristic = peripheral.characteristic("f000aa21-0451-4000-b000-000000000000"); 378 } 379 else { 380#ifdef DEBUG 381 Serial.println("Error: Humidity service discovery failed."); 382#endif 383 peripheral.disconnect(); 384 return; 385 } 386} 387 388// Sensor reads 389void read_BP(BLEDevice peripheral) { 390 uint8_t holdvalues[6]; 391 392 if (peripheral.connected()) { 393 // wake up the sensor 394 BPConCharacteristic.writeValue(sensorOn); 395 delay(1200); // wait for the sensor to do a read 396 BPValCharacteristic.readValue(holdvalues, 6); 397 unsigned long rawbptemp = (holdvalues[2] * 65536) + (holdvalues[1] * 256) + holdvalues[0]; 398 unsigned int rawbp = (holdvalues[5] * 65536) + (holdvalues[4] * 256) + holdvalues[3]; 399 // sleep sensor 400 BPConCharacteristic.writeValue(sensorOff); 401 // calculate temperature and pressure final values 402 float bptemp = ((double)rawbptemp / 100.0); 403 bptemp = ((bptemp * 9.0) / 5.0) + 32.0; // convert to F - comment out to leave at C 404 float bp = ((double)rawbp / 100.0); 405 // save into the structure 406 SensorData.bp = bp; 407 SensorData.bptemp = bptemp; 408 } 409 else { 410#ifdef DEBUG 411 Serial.println(" *not connected* "); 412#endif 413 } 414} 415 416void read_OPT(BLEDevice peripheral) { 417 // for this sensor the characteristic's value is read directly 418 // into rawlux and then processed. No array is used. 419 420 uint16_t rawlux; 421 422 if (peripheral.connected()) { 423 // wake up the sensor 424 OPTConCharacteristic.writeValue(sensorOn); 425 delay(1200); // wait for the sensor to do a read 426 OPTValCharacteristic.readValue(rawlux); 427 OPTConCharacteristic.writeValue(sensorOff); // sleep sensor 428 // calculate lux final value 429 unsigned int m = rawlux & 0x0FFF; 430 unsigned int e = (rawlux & 0xF000) >> 12; 431 float lux = (m * (0.01 * pow(2.0, e))); 432 // save into the structure 433 SensorData.li = lux; 434 } 435 else { 436#ifdef DEBUG 437 Serial.println(" *not connected* "); 438#endif 439 } 440} 441 442void read_IRT(BLEDevice peripheral) { 443 uint8_t holdvalues[4]; 444 445 if (peripheral.connected()) { 446 // wake up the sensor 447 IRTConCharacteristic.writeValue((uint8_t) 0x01); 448 delay(1200); // wait for the sensor to do a read 449 IRTValCharacteristic.readValue(holdvalues, 4); 450 unsigned int rawobj = (holdvalues[0]) + (holdvalues[1] * 256); 451 unsigned int rawamb = (holdvalues[2]) + (holdvalues[3] * 256); 452 IRTConCharacteristic.writeValue(sensorOff); // sleep sensor 453 // calculate final temperature values 454 const float SCALE_LSB = 0.03125; 455 int it = (int)( rawobj >> 2); 456 float IRTo = ( (float)it) * SCALE_LSB; 457 IRTo = ( (IRTo * 9.0) / 5.0 ) + 32.0; // convert to F - comment out to leave at C 458 it = (int)(rawamb >> 2); 459 float IRTa = (float)it * SCALE_LSB; 460 IRTa = ( (IRTa * 9.0) / 5.0) + 32.0; // convert to F - comment out to leave at C 461 // save into the structure 462 SensorData.temd = IRTa; 463 SensorData.temo = IRTo; 464 } 465 else { 466#ifdef DEBUG 467 Serial.println(" *not connected* "); 468#endif 469 } 470} 471 472void read_HUM(BLEDevice peripheral) { 473 uint8_t holdvalues[4]; // hold the characteristic's bytes 474 475 if (peripheral.connected()) { 476 // wake up sensor 477 HUMConCharacteristic.writeValue(sensorOn); 478 delay(1200); // wait for the sensor to do a read 479 HUMValCharacteristic.readValue(holdvalues, 4); 480 HUMConCharacteristic.writeValue(sensorOff); // sleep sensor 481 unsigned int rawtem = (holdvalues[0]) + (holdvalues[1] * 256); 482 unsigned int rawhum = (holdvalues[2]) + (holdvalues[3] * 256); 483 // calculate final temperature and relative humidity values 484 float temp = (rawtem / 65536.0) * 165.0 - 40.0; 485 temp = ((temp * 9.0) / 5.0) + 32.0; // convert to F - comment out to leave at C 486 float hum = ((double)rawhum / 65536.0) * 100.0; 487 // save into the structure 488 SensorData.tem = temp; 489 SensorData.hum = hum; 490 } 491 else { 492#ifdef DEBUG 493 Serial.println(" *not connected* "); 494#endif 495 } 496} 497 498// Print serial and screen and write SD routines 499void print_data() { 500 // Print the data to the serial moniter 501 // NOTE: the time vars could be slightly different than the SD card 502 // since they are two different routines but the Serial prints are 503 // mainly for debugging 504 505 String separator = ", "; 506 // Data Line as follow (with comma separator): 507 // epoch day, month, year, hours, minutes, seconds, HDC1000 temp, HDC1000 hum, 508 // BMP280 pressure, BMP280 tem, OPT3001 light (lux), TMP007 object temp, TMP007 temp 509#ifdef DEBUG 510 Serial.print(rtc.getEpoch()); 511 Serial.print(separator); 512 Serial.print(rtc.getDay()); 513 Serial.print(separator); 514 Serial.print(rtc.getMonth()); 515 Serial.print(separator); 516 Serial.print(rtc.getYear()); 517 Serial.print(separator); 518 printP02D(rtc.getHours()); 519 Serial.print(separator); 520 printP02D(rtc.getMinutes()); 521 Serial.print(separator); 522 printP02D(rtc.getSeconds()); 523 Serial.print(separator); 524 Serial.print(SensorData.tem); 525 Serial.print(separator); 526 Serial.print(SensorData.hum); 527 Serial.print(separator); 528 Serial.print(SensorData.bp); 529 Serial.print(separator); 530 Serial.print(SensorData.bptemp); 531 Serial.print(separator); 532 Serial.print(SensorData.li); 533 Serial.print(separator); 534 Serial.print(SensorData.temo); 535 Serial.print(separator); 536 Serial.print(SensorData.temd); 537 Serial.println(); 538 // end of data line 539#endif 540} 541 542void write_SDdata() { 543 // Write the data to the SD card 544 String separator = ", "; 545 546 // Data Line as follow (with comma separator): 547 // epoch day, month, year, hours, minutes, seconds, HDC1000 temp, HDC1000 hum, 548 // BMP280 pressure, BMP280 tem, OPT3001 light (lux), TMP007 temp, TMP0007 object temp 549 // open the file 550 SDF = SD.open(fname, FILE_WRITE); 551 if (!SDF) { 552 // terminal error if we can't open the SD File (we already initialized) 553 u8x8.clearDisplay(); 554 u8x8.drawString(0, 2 , "SD Card "); 555 u8x8.drawString(0, 3 , "Terminal Error!"); 556#ifdef DEBUG 557 Serial.println("SD card write failure!"); 558#endif 559 while (1); 560 } 561 else { 562 // write the separator-delimited data line 563 // comment out what you don't want e.g., 564 // epoch, day,mon,year,hour,min,sec, HDC tem, HDC hum, AP, BMP tem, Illum, TMP obj Tem, TMP tem 565 SDF.print(rtc.getEpoch()); 566 SDF.print(separator); 567 SDF.print(rtc.getDay()); 568 SDF.print(separator); 569 SDF.print(rtc.getMonth()); 570 SDF.print(separator); 571 SDF.print(rtc.getYear()); 572 SDF.print(separator); 573 SDF.print(rtc.getHours()); 574 SDF.print(separator); 575 SDF.print(rtc.getMinutes()); 576 SDF.print(separator); 577 SDF.print(rtc.getSeconds()); 578 SDF.print(separator); 579 SDF.print(SensorData.tem); 580 SDF.print(separator); 581 SDF.print(SensorData.hum); 582 SDF.print(separator); 583 SDF.print(SensorData.bp); 584 SDF.print(separator); 585 SDF.print(SensorData.bptemp); 586 SDF.print(separator); 587 SDF.print(SensorData.li); 588 SDF.print(separator); 589 SDF.print(SensorData.temo); 590 SDF.print(separator); 591 SDF.print(SensorData.temd); 592 SDF.println(); // Windows cr/lf 593 SDF.close(); 594 } 595} 596 597void print_screenT() { 598 // print the LCD template 599 u8x8.setFont(u8x8_font_px437wyse700a_2x2_f); // large for Tem/Hum 600 u8x8.drawString(0, 0, "T:"); 601 u8x8.drawUTF8(14, 0, degree); 602 u8x8.drawString(0, 2, "H:"); 603 u8x8.drawUTF8(14, 2, percent); 604 // back to smaller font for tyhe rest 605 u8x8.setFont(u8x8_font_amstrad_cpc_extended_f); 606 u8x8.drawString(0, 5, "AP:"); 607 //u8x8.drawString(0, 5, "BP: 0123 hPa"); 608 u8x8.setCursor(10, 5); 609 u8x8.print(" hPa"); 610 u8x8.drawString(0, 6, "IL:"); 611 u8x8.setCursor(10, 6); 612 u8x8.print(" lux"); 613 // alternative times current left 614 u8x8.drawString(0, 7, "00:00"); 615 u8x8.drawString(11, 7, "00:00"); 616} 617 618void print_screenValues() { 619 float Dtem, Dhum, Dap, Dli; 620 // call this *after* sensor structure has been updated 621 // first update the logged time? need small font 622 u8x8.setFont(u8x8_font_px437wyse700a_2x2_f); // large for Tem/Hum 623 // temperature 624 // sensor error check NOTE: read values will be printed to screen and SD 625 Dtem = SensorData.tem; 626 if (Dtem > 999.9) Dtem = 999.9; 627 if (Dtem < -99.9) Dtem = -99.9; 628 dtostrf(Dtem, 5, 1, p_buffer); // convert to 5 chars 1 after decimal 629 u8x8.setCursor(4, 0); 630 u8x8.print(p_buffer); 631 //u8x8.drawUTF8(14, 0, degree); degree sign has been done in 632 // humidity 633 // sensor error check 634 Dhum = SensorData.hum; 635 if (Dhum > 100.0) Dhum = 100.0; 636 if (Dhum < 0.0) Dhum = 0.0; 637 dtostrf(Dhum, 5, 1, p_buffer); // convert to 5 chars 1 after decimal 638 u8x8.setCursor(4, 2); 639 u8x8.print(p_buffer); 640 //u8x8.drawUTF8(14, 2, percent); already done in template print 641 // back to smaller font for tyhe rest 642 u8x8.setFont(u8x8_font_amstrad_cpc_extended_f); 643 // barometric pressure 644 // sensor error check 645 Dap = SensorData.bp; 646 if (Dap < 750.0) Dap = 000.0; 647 if (Dap > 1200.0) Dap = 9999.9; 648 dtostrf(Dap, 7, 1, p_buffer); // convert to 7 chars 1 after decimal 649 u8x8.setCursor(3, 5); 650 u8x8.print(p_buffer); 651 // Illuminance 652 // sensor error check 653 Dli = SensorData.li; 654 if (Dli > 99999.9) Dli = 99999.9; 655 if (Dli < 0.0) Dli = 0; 656 dtostrf(Dli, 7, 1, p_buffer); // convert to 7 chars 1 after decimal 657 u8x8.setCursor(3, 6); 658 u8x8.print(p_buffer); 659} 660 661void printclockD(byte side) { 662 // print the HH:SS of the current clock on the right or left side of the LCD 663 // must be in a small font! (could do this as a switch case) 664int hourT,minT; 665 666 switch (side) { 667 case 1: //left side 668 u8x8.setCursor(0, 7); 669 hourT = rtc.getHours(); 670 if (hourT < 10) { // pad hours <10 671 u8x8.drawString(0, 7 , "0"); 672 u8x8.setCursor(1, 7); 673 u8x8.print(hourT); 674 } 675 else { 676 u8x8.print(hourT); 677 } 678 // note the ':' is from the template 679 u8x8.setCursor(3, 7); 680 minT = rtc.getMinutes(); 681 if (minT < 10) { // pad seconds <10 682 u8x8.drawString(3, 7 , "0"); 683 u8x8.setCursor(4, 7); 684 u8x8.print(minT); 685 } 686 else { 687 u8x8.print(minT); 688 } 689 break; 690 case 2: // right side 691 u8x8.setCursor(11, 7); 692 hourT = rtc.getHours(); 693 if (hourT < 10) { // pad hours <10 694 u8x8.drawString(11, 7 , "0"); 695 u8x8.setCursor(12, 7); 696 u8x8.print(hourT); 697 } 698 else { 699 u8x8.print(hourT); 700 } 701 // note the ':' is from the template 702 u8x8.setCursor(14, 7); 703 minT = rtc.getMinutes(); 704 if (minT < 10) { // pad secondss <10 705 u8x8.drawString(14, 7 , "0"); 706 u8x8.setCursor(15, 7); 707 u8x8.print(minT); 708 } 709 else { 710 u8x8.print(minT); 711 } 712 break; 713 default: // can add other options 714 // statements 715 break; 716 } 717} 718 719void printWiFiStatus() { 720 // note: this will only be called if DEBUG is defines 721 Serial.print("SSID: "); 722 Serial.println(WiFi.SSID()); 723 IPAddress ip = WiFi.localIP(); 724 Serial.print("IP Address: "); 725 Serial.println(ip); 726 long rssi = WiFi.RSSI(); 727 Serial.print("signal strength (RSSI):"); 728 Serial.print(rssi); 729 Serial.println(" dBm"); 730} 731 732void printP02D(int number) { 733 if (number < 10) Serial.print('0'); 734 Serial.print(number); 735} 736 737// End of code 738
YADL_V1_0R
arduino
Complete program code for the data logger
1//********************************************************************************* 2// 3 YADL SensorTag Data Logger v1.0R [DrG] 4// ** This software is offered strictly 5 as is with no guarantees or warranties. ** 6// ** - USE IT AT YOUR OWN RISK! 7 ** 8//********************************************************************************* 9// 10// 11 Uses: 12// WiFiNINA v1.40 13// RTCZero 1.6.0 14// ArduinoBLE v1.1.1 15// SD 16 v1.2.3 17// U8g2 (U8x8) v2.26.14 18// 19// Arduino IDE v1.8.10 20// 21// Hardware: 22// 23 MKR1010 / NANO 33 IOT (both have been tested) 24// microSD card (both generics 25 and MicroElectronika click board tested) 26// HiLetgo 1.3" I2C monochrome OLED 27 (others should work with modification) 28// 29// Note: Replace the code entries 30 below with your network info: 31// char ssid[] = "XXXXXXXXXX"; 32// char pass[] 33 = "XXXXXXXXXX"; 34// 35// Note: set GMT (with DST if needed) in code entry: 36// 37 const int GMT =XX 38// 39// #includes 40#include <WiFiNINA.h> 41#include <RTCZero.h> 42#include 43 <ArduinoBLE.h> 44#include <SPI.h> 45#include <SD.h> 46#include <U8x8lib.h> 47#include 48 <avr/dtostrf.h> // needed for MKR1010 49 50//#define DEBUG // uncomment this 51 line for serial monitor output 52 53RTCZero rtc; 54BLEDevice peripheral; 55File 56 SDF; 57 58U8X8_SH1106_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE); 59 60// Global 61 structure to hold the sensor data 62struct DATA { 63 float tem; // HDC1000 64 temperature F 65 float hum; // HDC1000 relative humidity %RH 66 float bptemp; 67 // BMP 280 die temperature F 68 float bp; // BMP 280 barometric pressure 69 in hectoPascals (1 hPa = 100 Pa) 70 float li; // OPT3001 lux 71 float temd; 72 // TMP007 die temperature F 73 float temo; // TMP007 object temperature 74 F 75}; 76 77typedef struct DATA DATA; 78DATA SensorData; 79 80// for SensorTag 81 sensors 82uint8_t sensorOn = 1; 83uint8_t sensorOff = 0; 84 85// lcd vars 86char 87 degree[] = {0xb0, 0x00}; 88char percent[] = {0x25, 0x00}; 89char p_buffer[12] 90 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 91 92// clock change catcher 93int lastmin; 94 95// 96 for RTC 97unsigned long epoch; 98int numberOfTries = 0, maxTries = 6; 99 100int 101 status = WL_IDLE_STATUS; // WiFiNINA use 102 103// Common user-changeable switches 104const 105 int GMT = -2; //change this to adapt it to your time zone 106byte SDswitch = 1; 107 // SDswitch 1=ON (write to SD) or 0 (Do not write to SD) 108char fname[] = "STDATA.txt"; 109 // data log file Name 110 111//period defines the length of time between measurements 112 in milliseconds 113// note that this does not includes delays for sensor reads (~8.7 114 sec) 115long period = 600000L; // 10 minutes 116//long period = 5000L; // 5 sec 117 for testing 118 119char ssid[] = ""; // your network SSID (name) 120char pass[] 121 = ""; // your network password (use for WPA, or use as key for WEP) 122int keyIndex 123 = 0; // your network key Index number (needed only for WEP) 124 125// 126 SensorTag characteristic definitions 127// BMP280 128BLECharacteristic BPConCharacteristic; 129BLECharacteristic 130 BPValCharacteristic; 131// OPT3001 132BLECharacteristic OPTConCharacteristic; 133BLECharacteristic 134 OPTValCharacteristic; 135// TMP007 136BLECharacteristic IRTConCharacteristic; 137BLECharacteristic 138 IRTValCharacteristic; 139// HDC1000 140BLECharacteristic HUMConCharacteristic; 141BLECharacteristic 142 HUMValCharacteristic; 143//------------------------------------------------------------------ 144 145void 146 setup() { 147 u8x8.begin(); // start lcd driver, will clear display 148 u8x8.setFont(u8x8_font_amstrad_cpc_extended_f); 149 // 8 X 8 font 150 u8x8.drawString(0, 0, "YADL starting..."); 151#ifdef DEBUG 152 153 Serial.begin(9600); 154 delay(5000); // delay for user to open the serial monitor 155 156 Serial.println("YADL MKR1010/NANO IOT 33 SensorTag Data Logger"); 157 Serial.println(); 158#endif 159 160 // check the SD card 161 if (SDswitch == 1) { 162 if (!SD.begin(4)) { 163 164 u8x8.drawString(0, 2 , "No SD card!"); 165 u8x8.drawString(0, 3 , "Terminal 166 Error!"); 167#ifdef DEBUG 168 Serial.println("SD Card initialization failed!"); 169#endif 170 171 while (1); 172 } 173 else { 174 u8x8.drawString(0, 2 , "SD card 175 found. "); 176 delay(2000); // to let user know 177 u8x8.drawString(0, 178 2 , " "); 179#ifdef DEBUG 180 Serial.println("SD Card found"); 181#endif 182 183 } 184 } 185 else { 186 u8x8.drawString(0, 2 , "No SD card"); 187 u8x8.drawString(0, 188 3 , "option"); 189 delay(2000); // to let user know 190 u8x8.drawString(0, 191 2 , " "); 192 u8x8.drawString(0, 3 , " "); 193#ifdef DEBUG 194 195 Serial.println("No SD Card option"); 196#endif 197 } 198 delay(2000); // 199 to let user know about sd card 200 // check if the WiFi module works 201 if (WiFi.status() 202 == WL_NO_SHIELD) { 203#ifdef DEBUG 204 Serial.println("WiFi shield not present"); 205#endif 206 207 u8x8.drawString(0, 1 , "NO WiFi!"); 208 u8x8.drawString(0, 2 , "Terminal 209 Error!"); 210 // don't continue: 211 while (true); 212 } 213 214 // attempt 215 to connect to WiFi network: 216 u8x8.drawString(0, 2 , "Connecting....."); 217 218 while ( status != WL_CONNECTED) { 219#ifdef DEBUG 220 Serial.print("Attempting 221 to connect to SSID: "); 222 Serial.println(ssid); 223#endif 224 // Connect 225 to WPA/WPA2 network. Change this line if using open or WEP network: 226 status 227 = WiFi.begin(ssid, pass); 228 delay(10000); // wait 10 seconds for connection: 229 230 } 231 u8x8.drawString(0, 3 , "Connected! "); 232#ifdef DEBUG 233 printWiFiStatus(); 234 // you're connected now, so print out the status: 235#endif 236 rtc.begin(); 237 238 do { 239 epoch = WiFi.getTime(); 240 numberOfTries++; 241 } 242 while 243 ((epoch == 0) && (numberOfTries < maxTries)); 244 245 if (numberOfTries == maxTries) 246 { 247 u8x8.drawString(0, 4 , "NTP Unreachable"); 248 u8x8.drawString(0, 249 5 , "TERMINAL ERROR!"); 250#ifdef DEBUG 251 Serial.print("NTP unreachable!!"); 252#endif 253 254 while (1); 255 } 256 else { 257 u8x8.drawString(0, 4 , "Got NTP Epoch 258 "); 259 epoch = epoch + (GMT * 3600UL); // adjust offset for TZ/DST 260 rtc.setEpoch(epoch); 261#ifdef 262 DEBUG 263 Serial.print("Epoch received: "); 264 Serial.print(epoch); 265 266 Serial.print(" "); 267 printP02D(rtc.getHours()); 268 Serial.print(":"); 269 270 printP02D(rtc.getMinutes()); 271 Serial.print(":"); 272 printP02D(rtc.getSeconds()); 273 274 Serial.print(" "); 275 Serial.print(rtc.getDay()); 276 Serial.print("/"); 277 278 Serial.print(rtc.getMonth()); 279 Serial.print("/"); 280 Serial.print(rtc.getYear()); 281 282 Serial.println(); 283#endif 284 WiFi.end(); 285 delay(15000); 286 u8x8.drawString(0, 287 5 , "WiFi Ended "); 288 u8x8.drawString(0, 6 , "Starting BLE "); 289 290 delay(2000); // to see it on the screen 291#ifdef DEBUG 292 Serial.println("WiFi.end 293 executed"); 294#endif 295 } 296 // Try to initialize BLE 297 if (!BLE.begin()) 298 { 299 Serial.println("Terminal Error: Could not start BLE!"); 300 u8x8.clear(); 301 302 u8x8.drawString(0, 0 , "BLE Start Fail"); 303 u8x8.drawString(0, 1 , "Terminal 304 Error!"); 305 while (1); 306 } 307 BLE.scan(); 308 u8x8.clear(); 309 u8x8.drawString(0, 310 0 , "Scanning......"); 311} 312//------------------------------------------------------------------ 313void 314 loop() { 315 long lastMillis = 0; // for period test 316 long nowMillis = 0; 317 // for period test 318 319 // check if a peripheral has been discovered 320 321 peripheral = BLE.available(); 322 if (peripheral) { 323 // discovered a peripheral, 324 print out address and local name 325#ifdef DEBUG 326 Serial.print("Found "); 327 328 Serial.print(peripheral.address()); 329 Serial.print(" '"); 330 Serial.print(peripheral.localName()); 331 332 Serial.println("' "); 333#endif 334 if (peripheral.localName() == "CC2650 335 SensorTag") { 336 BLE.stopScan(); // stop scanning 337 // connect to 338 the peripheral 339 u8x8.drawString(0, 1 , "Connecting...."); 340#ifdef DEBUG 341 342 Serial.print("Connecting to SensorTag ..."); 343#endif 344 if (peripheral.connect()) 345 { 346 u8x8.drawString(0, 2 , "Connected....."); 347#ifdef DEBUG 348 Serial.println("Connected..."); 349#endif 350 351 do_discovery(peripheral); 352 // Note: we do not subscribe to any 353 services because we are not using notify 354 u8x8.clear(); 355 print_screenT(); 356#ifdef 357 DEBUG 358 Serial.println("Reading sensors..."); 359 Serial.println(); 360#endif 361 362 } 363 else { 364 u8x8.drawString(0, 2 , "Scanning......"); 365#ifdef 366 DEBUG 367 Serial.println(" scanning"); 368#endif 369 } 370 } 371 372 // main while connected loop 373 while (peripheral.connected()) { 374 read_BP(peripheral); 375 376 read_OPT(peripheral); 377 read_IRT(peripheral); 378 read_HUM(peripheral); 379 380 if (SDswitch) write_SDdata(); // write data to sd card 381 // screen 382 for debug no print here as well 383#ifdef DEBUG 384 print_data(); 385#endif 386 387 print_screenValues(); 388 printclockD(1); // Update sensor clock 389 390 printclockD(2); // update current clock 391 lastmin = rtc.getMinutes(); 392 393 lastMillis = millis(); 394 // stay here until the period is up 395 // 396 update current time here 397 while ( ( (nowMillis = millis()) - lastMillis) 398 <= period) { 399 // need to update the clock here 400 if (lastmin 401 != rtc.getMinutes()) { 402 lastmin = rtc.getMinutes(); 403 printclockD(2); 404 // update current clock 405 } 406 } 407 } 408 // peripheral disconnected, 409 start scanning again 410 u8x8.clear(); 411 u8x8.drawString(0, 2 , "Scanning......"); 412#ifdef 413 DEBUG 414 Serial.println(" - rescan..."); 415#endif 416 BLE.scan(); 417 418 } 419} 420//------------------------------------------------------------------ 421 422// 423 BLE SensorTag routines 424void do_discovery(BLEDevice peripheral) { 425 // discover 426 the peripheral's attributes that we want 427 // barometric 428#ifdef DEBUG 429 430 Serial.print("Discovering attributes for Barometric Pressure service ..."); 431#endif 432 433 if (peripheral.discoverService("f000aa40-0451-4000-b000-000000000000")) { 434#ifdef 435 DEBUG 436 Serial.println("discovered"); 437#endif 438 BPConCharacteristic 439 = peripheral.characteristic("f000aa42-0451-4000-b000-000000000000"); 440 BPValCharacteristic 441 = peripheral.characteristic("f000aa41-0451-4000-b000-000000000000"); 442 } 443 444 else { 445#ifdef DEBUG 446 Serial.println("ERROR: Barometric Pressure service 447 discovery failed."); 448#endif 449 peripheral.disconnect(); 450 return; 451 452 } 453 // discover the peripheral's attributes that we want 454 // optical sensor 455#ifdef 456 DEBUG 457 Serial.print("Discovering attributes for Luxometer service ..."); 458#endif 459 460 if (peripheral.discoverService("f000aa70-0451-4000-b000-000000000000")) { 461#ifdef 462 DEBUG 463 Serial.println("discovered"); 464#endif 465 OPTConCharacteristic 466 = peripheral.characteristic("f000aa72-0451-4000-b000-000000000000"); 467 OPTValCharacteristic 468 = peripheral.characteristic("f000aa71-0451-4000-b000-000000000000"); 469 } 470 471 else { 472#ifdef DEBUG 473 Serial.println("Error: Luxometer service discovery 474 failed."); 475#endif 476 peripheral.disconnect(); 477 return; 478 } 479 480 // IR 481#ifdef DEBUG 482 Serial.print("Discovering attributes for Infrared 483 service ..."); 484#endif 485 if (peripheral.discoverService("f000aa00-0451-4000-b000-000000000000")) 486 { 487#ifdef DEBUG 488 Serial.println("discovered"); 489#endif 490 IRTConCharacteristic 491 = peripheral.characteristic("f000aa02-0451-4000-b000-000000000000"); 492 IRTValCharacteristic 493 = peripheral.characteristic("f000aa01-0451-4000-b000-000000000000"); 494 } 495 496 else { 497#ifdef DEBUG 498 Serial.println("Error: Infrared service discovery 499 failed."); 500#endif 501 peripheral.disconnect(); 502 return; 503 } 504 505 // humidity 506#ifdef DEBUG 507 Serial.print("Discovering attributes for Humidity 508 service ..."); 509#endif 510 if (peripheral.discoverService("f000aa20-0451-4000-b000-000000000000")) 511 { 512#ifdef DEBUG 513 Serial.println("discovered"); 514#endif 515 HUMConCharacteristic 516 = peripheral.characteristic("f000aa22-0451-4000-b000-000000000000"); 517 HUMValCharacteristic 518 = peripheral.characteristic("f000aa21-0451-4000-b000-000000000000"); 519 } 520 521 else { 522#ifdef DEBUG 523 Serial.println("Error: Humidity service discovery 524 failed."); 525#endif 526 peripheral.disconnect(); 527 return; 528 } 529} 530 531// 532 Sensor reads 533void read_BP(BLEDevice peripheral) { 534 uint8_t holdvalues[6]; 535 536 537 if (peripheral.connected()) { 538 // wake up the sensor 539 BPConCharacteristic.writeValue(sensorOn); 540 541 delay(1200); // wait for the sensor to do a read 542 BPValCharacteristic.readValue(holdvalues, 543 6); 544 unsigned long rawbptemp = (holdvalues[2] * 65536) + (holdvalues[1] * 545 256) + holdvalues[0]; 546 unsigned int rawbp = (holdvalues[5] * 65536) + (holdvalues[4] 547 * 256) + holdvalues[3]; 548 // sleep sensor 549 BPConCharacteristic.writeValue(sensorOff); 550 551 // calculate temperature and pressure final values 552 float bptemp = ((double)rawbptemp 553 / 100.0); 554 bptemp = ((bptemp * 9.0) / 5.0) + 32.0; // convert to F - comment 555 out to leave at C 556 float bp = ((double)rawbp / 100.0); 557 // save into 558 the structure 559 SensorData.bp = bp; 560 SensorData.bptemp = bptemp; 561 562 } 563 else { 564#ifdef DEBUG 565 Serial.println(" *not connected* "); 566#endif 567 568 } 569} 570 571void read_OPT(BLEDevice peripheral) { 572 // for this sensor the 573 characteristic's value is read directly 574 // into rawlux and then processed. 575 No array is used. 576 577 uint16_t rawlux; 578 579 if (peripheral.connected()) 580 { 581 // wake up the sensor 582 OPTConCharacteristic.writeValue(sensorOn); 583 584 delay(1200); // wait for the sensor to do a read 585 OPTValCharacteristic.readValue(rawlux); 586 587 OPTConCharacteristic.writeValue(sensorOff); // sleep sensor 588 // calculate 589 lux final value 590 unsigned int m = rawlux & 0x0FFF; 591 unsigned int e = 592 (rawlux & 0xF000) >> 12; 593 float lux = (m * (0.01 * pow(2.0, e))); 594 // 595 save into the structure 596 SensorData.li = lux; 597 } 598 else { 599#ifdef 600 DEBUG 601 Serial.println(" *not connected* "); 602#endif 603 } 604} 605 606void 607 read_IRT(BLEDevice peripheral) { 608 uint8_t holdvalues[4]; 609 610 if (peripheral.connected()) 611 { 612 // wake up the sensor 613 IRTConCharacteristic.writeValue((uint8_t) 614 0x01); 615 delay(1200); // wait for the sensor to do a read 616 IRTValCharacteristic.readValue(holdvalues, 617 4); 618 unsigned int rawobj = (holdvalues[0]) + (holdvalues[1] * 256); 619 unsigned 620 int rawamb = (holdvalues[2]) + (holdvalues[3] * 256); 621 IRTConCharacteristic.writeValue(sensorOff); 622 // sleep sensor 623 // calculate final temperature values 624 const float 625 SCALE_LSB = 0.03125; 626 int it = (int)( rawobj >> 2); 627 float IRTo = ( 628 (float)it) * SCALE_LSB; 629 IRTo = ( (IRTo * 9.0) / 5.0 ) + 32.0; // convert 630 to F - comment out to leave at C 631 it = (int)(rawamb >> 2); 632 float IRTa 633 = (float)it * SCALE_LSB; 634 IRTa = ( (IRTa * 9.0) / 5.0) + 32.0; // convert 635 to F - comment out to leave at C 636 // save into the structure 637 SensorData.temd 638 = IRTa; 639 SensorData.temo = IRTo; 640 } 641 else { 642#ifdef DEBUG 643 Serial.println(" 644 *not connected* "); 645#endif 646 } 647} 648 649void read_HUM(BLEDevice peripheral) 650 { 651 uint8_t holdvalues[4]; // hold the characteristic's bytes 652 653 if (peripheral.connected()) 654 { 655 // wake up sensor 656 HUMConCharacteristic.writeValue(sensorOn); 657 658 delay(1200); // wait for the sensor to do a read 659 HUMValCharacteristic.readValue(holdvalues, 660 4); 661 HUMConCharacteristic.writeValue(sensorOff); // sleep sensor 662 unsigned 663 int rawtem = (holdvalues[0]) + (holdvalues[1] * 256); 664 unsigned int rawhum 665 = (holdvalues[2]) + (holdvalues[3] * 256); 666 // calculate final temperature 667 and relative humidity values 668 float temp = (rawtem / 65536.0) * 165.0 - 40.0; 669 670 temp = ((temp * 9.0) / 5.0) + 32.0; // convert to F - comment out to leave at 671 C 672 float hum = ((double)rawhum / 65536.0) * 100.0; 673 // save into the 674 structure 675 SensorData.tem = temp; 676 SensorData.hum = hum; 677 } 678 679 else { 680#ifdef DEBUG 681 Serial.println(" *not connected* "); 682#endif 683 684 } 685} 686 687// Print serial and screen and write SD routines 688void print_data() 689 { 690 // Print the data to the serial moniter 691 // NOTE: the time vars could 692 be slightly different than the SD card 693 // since they are two different routines 694 but the Serial prints are 695 // mainly for debugging 696 697 String separator 698 = ", "; 699 // Data Line as follow (with comma separator): 700 // epoch day, 701 month, year, hours, minutes, seconds, HDC1000 temp, HDC1000 hum, 702 // BMP280 703 pressure, BMP280 tem, OPT3001 light (lux), TMP007 object temp, TMP007 temp 704#ifdef 705 DEBUG 706 Serial.print(rtc.getEpoch()); 707 Serial.print(separator); 708 Serial.print(rtc.getDay()); 709 710 Serial.print(separator); 711 Serial.print(rtc.getMonth()); 712 Serial.print(separator); 713 714 Serial.print(rtc.getYear()); 715 Serial.print(separator); 716 printP02D(rtc.getHours()); 717 718 Serial.print(separator); 719 printP02D(rtc.getMinutes()); 720 Serial.print(separator); 721 722 printP02D(rtc.getSeconds()); 723 Serial.print(separator); 724 Serial.print(SensorData.tem); 725 726 Serial.print(separator); 727 Serial.print(SensorData.hum); 728 Serial.print(separator); 729 730 Serial.print(SensorData.bp); 731 Serial.print(separator); 732 Serial.print(SensorData.bptemp); 733 734 Serial.print(separator); 735 Serial.print(SensorData.li); 736 Serial.print(separator); 737 738 Serial.print(SensorData.temo); 739 Serial.print(separator); 740 Serial.print(SensorData.temd); 741 742 Serial.println(); 743 // end of data line 744#endif 745} 746 747void write_SDdata() 748 { 749 // Write the data to the SD card 750 String separator = ", "; 751 752 753 // Data Line as follow (with comma separator): 754 // epoch day, month, year, 755 hours, minutes, seconds, HDC1000 temp, HDC1000 hum, 756 // BMP280 pressure, BMP280 757 tem, OPT3001 light (lux), TMP007 temp, TMP0007 object temp 758 // open the file 759 760 SDF = SD.open(fname, FILE_WRITE); 761 if (!SDF) { 762 // terminal error if 763 we can't open the SD File (we already initialized) 764 u8x8.clearDisplay(); 765 766 u8x8.drawString(0, 2 , "SD Card "); 767 u8x8.drawString(0, 3 , "Terminal 768 Error!"); 769#ifdef DEBUG 770 Serial.println("SD card write failure!"); 771#endif 772 773 while (1); 774 } 775 else { 776 // write the separator-delimited data line 777 778 // comment out what you don't want e.g., 779 // epoch, day,mon,year,hour,min,sec, 780 HDC tem, HDC hum, AP, BMP tem, Illum, TMP obj Tem, TMP tem 781 SDF.print(rtc.getEpoch()); 782 783 SDF.print(separator); 784 SDF.print(rtc.getDay()); 785 SDF.print(separator); 786 787 SDF.print(rtc.getMonth()); 788 SDF.print(separator); 789 SDF.print(rtc.getYear()); 790 791 SDF.print(separator); 792 SDF.print(rtc.getHours()); 793 SDF.print(separator); 794 795 SDF.print(rtc.getMinutes()); 796 SDF.print(separator); 797 SDF.print(rtc.getSeconds()); 798 799 SDF.print(separator); 800 SDF.print(SensorData.tem); 801 SDF.print(separator); 802 803 SDF.print(SensorData.hum); 804 SDF.print(separator); 805 SDF.print(SensorData.bp); 806 807 SDF.print(separator); 808 SDF.print(SensorData.bptemp); 809 SDF.print(separator); 810 811 SDF.print(SensorData.li); 812 SDF.print(separator); 813 SDF.print(SensorData.temo); 814 815 SDF.print(separator); 816 SDF.print(SensorData.temd); 817 SDF.println(); 818 // Windows cr/lf 819 SDF.close(); 820 } 821} 822 823void print_screenT() { 824 825 // print the LCD template 826 u8x8.setFont(u8x8_font_px437wyse700a_2x2_f); // 827 large for Tem/Hum 828 u8x8.drawString(0, 0, "T:"); 829 u8x8.drawUTF8(14, 0, 830 degree); 831 u8x8.drawString(0, 2, "H:"); 832 u8x8.drawUTF8(14, 2, percent); 833 834 // back to smaller font for tyhe rest 835 u8x8.setFont(u8x8_font_amstrad_cpc_extended_f); 836 837 u8x8.drawString(0, 5, "AP:"); 838 //u8x8.drawString(0, 5, "BP: 0123 hPa"); 839 840 u8x8.setCursor(10, 5); 841 u8x8.print(" hPa"); 842 u8x8.drawString(0, 6, "IL:"); 843 844 u8x8.setCursor(10, 6); 845 u8x8.print(" lux"); 846 // alternative times current 847 left 848 u8x8.drawString(0, 7, "00:00"); 849 u8x8.drawString(11, 7, "00:00"); 850} 851 852void 853 print_screenValues() { 854 float Dtem, Dhum, Dap, Dli; 855 // call this *after* 856 sensor structure has been updated 857 // first update the logged time? need small 858 font 859 u8x8.setFont(u8x8_font_px437wyse700a_2x2_f); // large for Tem/Hum 860 861 // temperature 862 // sensor error check NOTE: read values will be printed to 863 screen and SD 864 Dtem = SensorData.tem; 865 if (Dtem > 999.9) Dtem = 999.9; 866 867 if (Dtem < -99.9) Dtem = -99.9; 868 dtostrf(Dtem, 5, 1, p_buffer); // convert 869 to 5 chars 1 after decimal 870 u8x8.setCursor(4, 0); 871 u8x8.print(p_buffer); 872 873 //u8x8.drawUTF8(14, 0, degree); degree sign has been done in 874 // humidity 875 876 // sensor error check 877 Dhum = SensorData.hum; 878 if (Dhum > 100.0) Dhum 879 = 100.0; 880 if (Dhum < 0.0) Dhum = 0.0; 881 dtostrf(Dhum, 5, 1, p_buffer); // 882 convert to 5 chars 1 after decimal 883 u8x8.setCursor(4, 2); 884 u8x8.print(p_buffer); 885 886 //u8x8.drawUTF8(14, 2, percent); already done in template print 887 // back 888 to smaller font for tyhe rest 889 u8x8.setFont(u8x8_font_amstrad_cpc_extended_f); 890 891 // barometric pressure 892 // sensor error check 893 Dap = SensorData.bp; 894 895 if (Dap < 750.0) Dap = 000.0; 896 if (Dap > 1200.0) Dap = 9999.9; 897 dtostrf(Dap, 898 7, 1, p_buffer); // convert to 7 chars 1 after decimal 899 u8x8.setCursor(3, 5); 900 901 u8x8.print(p_buffer); 902 // Illuminance 903 // sensor error check 904 Dli 905 = SensorData.li; 906 if (Dli > 99999.9) Dli = 99999.9; 907 if (Dli < 0.0) Dli 908 = 0; 909 dtostrf(Dli, 7, 1, p_buffer); // convert to 7 chars 1 after decimal 910 911 u8x8.setCursor(3, 6); 912 u8x8.print(p_buffer); 913} 914 915void printclockD(byte 916 side) { 917 // print the HH:SS of the current clock on the right or left side of 918 the LCD 919 // must be in a small font! (could do this as a switch case) 920int 921 hourT,minT; 922 923 switch (side) { 924 case 1: //left side 925 u8x8.setCursor(0, 926 7); 927 hourT = rtc.getHours(); 928 if (hourT < 10) { // pad hours <10 929 930 u8x8.drawString(0, 7 , "0"); 931 u8x8.setCursor(1, 7); 932 u8x8.print(hourT); 933 934 } 935 else { 936 u8x8.print(hourT); 937 } 938 // note 939 the ':' is from the template 940 u8x8.setCursor(3, 7); 941 minT = rtc.getMinutes(); 942 943 if (minT < 10) { // pad seconds <10 944 u8x8.drawString(3, 7 , "0"); 945 946 u8x8.setCursor(4, 7); 947 u8x8.print(minT); 948 } 949 else 950 { 951 u8x8.print(minT); 952 } 953 break; 954 case 2: // right 955 side 956 u8x8.setCursor(11, 7); 957 hourT = rtc.getHours(); 958 if 959 (hourT < 10) { // pad hours <10 960 u8x8.drawString(11, 7 , "0"); 961 u8x8.setCursor(12, 962 7); 963 u8x8.print(hourT); 964 } 965 else { 966 u8x8.print(hourT); 967 968 } 969 // note the ':' is from the template 970 u8x8.setCursor(14, 971 7); 972 minT = rtc.getMinutes(); 973 if (minT < 10) { // pad secondss 974 <10 975 u8x8.drawString(14, 7 , "0"); 976 u8x8.setCursor(15, 7); 977 978 u8x8.print(minT); 979 } 980 else { 981 u8x8.print(minT); 982 983 } 984 break; 985 default: // can add other options 986 // statements 987 988 break; 989 } 990} 991 992void printWiFiStatus() { 993 // note: this will 994 only be called if DEBUG is defines 995 Serial.print("SSID: "); 996 Serial.println(WiFi.SSID()); 997 998 IPAddress ip = WiFi.localIP(); 999 Serial.print("IP Address: "); 1000 Serial.println(ip); 1001 1002 long rssi = WiFi.RSSI(); 1003 Serial.print("signal strength (RSSI):"); 1004 Serial.print(rssi); 1005 1006 Serial.println(" dBm"); 1007} 1008 1009void printP02D(int number) { 1010 if (number 1011 < 10) Serial.print('0'); 1012 Serial.print(number); 1013} 1014 1015// End of code 1016
YADL v1.0R
arduino
Complete Program Code for the Data Logger
1//********************************************************************************* 2// YADL SensorTag Data Logger v1.0R [DrG] 3// ** This software is offered strictly as is with no guarantees or warranties. ** 4// ** - USE IT AT YOUR OWN RISK! ** 5//********************************************************************************* 6// 7// Uses: 8// WiFiNINA v1.40 9// RTCZero 1.6.0 10// ArduinoBLE v1.1.1 11// SD v1.2.3 12// U8g2 (U8x8) v2.26.14 13// 14// Arduino IDE v1.8.10 15// 16// Hardware: 17// MKR1010 / NANO 33 IOT (both have been tested) 18// microSD card (both generics and MicroElectronika click board tested) 19// HiLetgo 1.3" I2C monochrome OLED (others should work with modification) 20// 21// Note: Replace the code entries below with your network info: 22// char ssid[] = "XXXXXXXXXX"; 23// char pass[] = "XXXXXXXXXX"; 24// 25// Note: set GMT (with DST if needed) in code entry: 26// const int GMT =XX 27// 28// #includes 29#include <WiFiNINA.h> 30#include <RTCZero.h> 31#include <ArduinoBLE.h> 32#include <SPI.h> 33#include <SD.h> 34#include <U8x8lib.h> 35#include <avr/dtostrf.h> // needed for MKR1010 36 37//#define DEBUG // uncomment this line for serial monitor output 38 39RTCZero rtc; 40BLEDevice peripheral; 41File SDF; 42 43U8X8_SH1106_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE); 44 45// Global structure to hold the sensor data 46struct DATA { 47 float tem; // HDC1000 temperature F 48 float hum; // HDC1000 relative humidity %RH 49 float bptemp; // BMP 280 die temperature F 50 float bp; // BMP 280 barometric pressure in hectoPascals (1 hPa = 100 Pa) 51 float li; // OPT3001 lux 52 float temd; // TMP007 die temperature F 53 float temo; // TMP007 object temperature F 54}; 55 56typedef struct DATA DATA; 57DATA SensorData; 58 59// for SensorTag sensors 60uint8_t sensorOn = 1; 61uint8_t sensorOff = 0; 62 63// lcd vars 64char degree[] = {0xb0, 0x00}; 65char percent[] = {0x25, 0x00}; 66char p_buffer[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 67 68// clock change catcher 69int lastmin; 70 71// for RTC 72unsigned long epoch; 73int numberOfTries = 0, maxTries = 6; 74 75int status = WL_IDLE_STATUS; // WiFiNINA use 76 77// Common user-changeable switches 78const int GMT = -4; //change this to adapt it to your time zone 79byte SDswitch = 1; // SDswitch 1=ON (write to SD) or 0 (Do not write to SD) 80char fname[] = "STDATA.txt"; // data log file Name 81 82//period defines the length of time between measurements in milliseconds 83// note that this does not includes delays for sensor reads (~8.7 sec) 84long period = 600000L; // 10 minutes 85//long period = 5000L; // 5 sec for testing 86 87char ssid[] = ""; // your network SSID (name) 88char pass[] = ""; // your network password (use for WPA, or use as key for WEP) 89int keyIndex = 0; // your network key Index number (needed only for WEP) 90 91// SensorTag characteristic definitions 92// BMP280 93BLECharacteristic BPConCharacteristic; 94BLECharacteristic BPValCharacteristic; 95// OPT3001 96BLECharacteristic OPTConCharacteristic; 97BLECharacteristic OPTValCharacteristic; 98// TMP007 99BLECharacteristic IRTConCharacteristic; 100BLECharacteristic IRTValCharacteristic; 101// HDC1000 102BLECharacteristic HUMConCharacteristic; 103BLECharacteristic HUMValCharacteristic; 104//------------------------------------------------------------------ 105 106void setup() { 107 u8x8.begin(); // start lcd driver, will clear display 108 u8x8.setFont(u8x8_font_amstrad_cpc_extended_f); // 8 X 8 font 109 u8x8.drawString(0, 0, "YADL starting..."); 110#ifdef DEBUG 111 Serial.begin(9600); 112 delay(5000); // delay for user to open the serial monitor 113 Serial.println("YADL MKR1010/NANO IOT 33 SensorTag Data Logger"); 114 Serial.println(); 115#endif 116 // check the SD card 117 if (SDswitch == 1) { 118 if (!SD.begin(4)) { 119 u8x8.drawString(0, 2 , "No SD card!"); 120 u8x8.drawString(0, 3 , "Terminal Error!"); 121#ifdef DEBUG 122 Serial.println("SD Card initialization failed!"); 123#endif 124 while (1); 125 } 126 else { 127 u8x8.drawString(0, 2 , "SD card found. "); 128 delay(2000); // to let user know 129 u8x8.drawString(0, 2 , " "); 130#ifdef DEBUG 131 Serial.println("SD Card found"); 132#endif 133 } 134 } 135 else { 136 u8x8.drawString(0, 2 , "No SD card"); 137 u8x8.drawString(0, 3 , "option"); 138 delay(2000); // to let user know 139 u8x8.drawString(0, 2 , " "); 140 u8x8.drawString(0, 3 , " "); 141#ifdef DEBUG 142 Serial.println("No SD Card option"); 143#endif 144 } 145 delay(2000); // to let user know about sd card 146 // check if the WiFi module works 147 if (WiFi.status() == WL_NO_SHIELD) { 148#ifdef DEBUG 149 Serial.println("WiFi shield not present"); 150#endif 151 u8x8.drawString(0, 1 , "NO WiFi!"); 152 u8x8.drawString(0, 2 , "Terminal Error!"); 153 // don't continue: 154 while (true); 155 } 156 157 // attempt to connect to WiFi network: 158 u8x8.drawString(0, 2 , "Connecting....."); 159 while ( status != WL_CONNECTED) { 160#ifdef DEBUG 161 Serial.print("Attempting to connect to SSID: "); 162 Serial.println(ssid); 163#endif 164 // Connect to WPA/WPA2 network. Change this line if using open or WEP network: 165 status = WiFi.begin(ssid, pass); 166 delay(10000); // wait 10 seconds for connection: 167 } 168 u8x8.drawString(0, 3 , "Connected! "); 169#ifdef DEBUG 170 printWiFiStatus(); // you're connected now, so print out the status: 171#endif 172 rtc.begin(); 173 do { 174 epoch = WiFi.getTime(); 175 numberOfTries++; 176 } 177 while ((epoch == 0) && (numberOfTries < maxTries)); 178 179 if (numberOfTries == maxTries) { 180 u8x8.drawString(0, 4 , "NTP Unreachable"); 181 u8x8.drawString(0, 5 , "TERMINAL ERROR!"); 182#ifdef DEBUG 183 Serial.print("NTP unreachable!!"); 184#endif 185 while (1); 186 } 187 else { 188 u8x8.drawString(0, 4 , "Got NTP Epoch "); 189 epoch = epoch + (GMT * 3600UL); // adjust offset for TZ/DST 190 rtc.setEpoch(epoch); 191#ifdef DEBUG 192 Serial.print("Epoch received: "); 193 Serial.print(epoch); 194 Serial.print(" "); 195 printP02D(rtc.getHours()); 196 Serial.print(":"); 197 printP02D(rtc.getMinutes()); 198 Serial.print(":"); 199 printP02D(rtc.getSeconds()); 200 Serial.print(" "); 201 Serial.print(rtc.getDay()); 202 Serial.print("/"); 203 Serial.print(rtc.getMonth()); 204 Serial.print("/"); 205 Serial.print(rtc.getYear()); 206 Serial.println(); 207#endif 208 WiFi.end(); 209 delay(15000); 210 u8x8.drawString(0, 5 , "WiFi Ended "); 211 u8x8.drawString(0, 6 , "Starting BLE "); 212 delay(2000); // to see it on the screen 213#ifdef DEBUG 214 Serial.println("WiFi.end executed"); 215#endif 216 } 217 // Try to initialize BLE 218 if (!BLE.begin()) { 219 Serial.println("Terminal Error: Could not start BLE!"); 220 u8x8.clear(); 221 u8x8.drawString(0, 0 , "BLE Start Fail"); 222 u8x8.drawString(0, 1 , "Terminal Error!"); 223 while (1); 224 } 225 BLE.scan(); 226 u8x8.clear(); 227 u8x8.drawString(0, 0 , "Scanning......"); 228} 229//------------------------------------------------------------------ 230void loop() { 231 long lastMillis = 0; // for period test 232 long nowMillis = 0; // for period test 233 234 // check if a peripheral has been discovered 235 peripheral = BLE.available(); 236 if (peripheral) { 237 // discovered a peripheral, print out address and local name 238#ifdef DEBUG 239 Serial.print("Found "); 240 Serial.print(peripheral.address()); 241 Serial.print(" '"); 242 Serial.print(peripheral.localName()); 243 Serial.println("' "); 244#endif 245 if (peripheral.localName() == "CC2650 SensorTag") { 246 BLE.stopScan(); // stop scanning 247 // connect to the peripheral 248 u8x8.drawString(0, 1 , "Connecting...."); 249#ifdef DEBUG 250 Serial.print("Connecting to SensorTag ..."); 251#endif 252 if (peripheral.connect()) { 253 u8x8.drawString(0, 2 , "Connected....."); 254#ifdef DEBUG 255 Serial.println("Connected..."); 256#endif 257 do_discovery(peripheral); 258 // Note: we do not subscribe to any services because we are not using notify 259 u8x8.clear(); 260 print_screenT(); 261#ifdef DEBUG 262 Serial.println("Reading sensors..."); 263 Serial.println(); 264#endif 265 } 266 else { 267 u8x8.drawString(0, 2 , "Scanning......"); 268#ifdef DEBUG 269 Serial.println(" scanning"); 270#endif 271 } 272 } 273 // main while connected loop 274 while (peripheral.connected()) { 275 read_BP(peripheral); 276 read_OPT(peripheral); 277 read_IRT(peripheral); 278 read_HUM(peripheral); 279 if (SDswitch) write_SDdata(); // write data to sd card 280 // screen for debug no print here as well 281#ifdef DEBUG 282 print_data(); 283#endif 284 print_screenValues(); 285 printclockD(1); // Update sensor clock 286 printclockD(2); // update current clock 287 lastmin = rtc.getMinutes(); 288 lastMillis = millis(); 289 // stay here until the period is up 290 // update current time here 291 while ( ( (nowMillis = millis()) - lastMillis) <= period) { 292 // need to update the clock here 293 if (lastmin != rtc.getMinutes()) { 294 lastmin = rtc.getMinutes(); 295 printclockD(2); // update current clock 296 } 297 } 298 } 299 // peripheral disconnected, start scanning again 300 u8x8.clear(); 301 u8x8.drawString(0, 2 , "Scanning......"); 302#ifdef DEBUG 303 Serial.println(" - rescan..."); 304#endif 305 BLE.scan(); 306 } 307} 308//------------------------------------------------------------------ 309 310// BLE SensorTag routines 311void do_discovery(BLEDevice peripheral) { 312 // discover the peripheral's attributes that we want 313 // barometric 314#ifdef DEBUG 315 Serial.print("Discovering attributes for Barometric Pressure service ..."); 316#endif 317 if (peripheral.discoverService("f000aa40-0451-4000-b000-000000000000")) { 318#ifdef DEBUG 319 Serial.println("discovered"); 320#endif 321 BPConCharacteristic = peripheral.characteristic("f000aa42-0451-4000-b000-000000000000"); 322 BPValCharacteristic = peripheral.characteristic("f000aa41-0451-4000-b000-000000000000"); 323 } 324 else { 325#ifdef DEBUG 326 Serial.println("ERROR: Barometric Pressure service discovery failed."); 327#endif 328 peripheral.disconnect(); 329 return; 330 } 331 // discover the peripheral's attributes that we want 332 // optical sensor 333#ifdef DEBUG 334 Serial.print("Discovering attributes for Luxometer service ..."); 335#endif 336 if (peripheral.discoverService("f000aa70-0451-4000-b000-000000000000")) { 337#ifdef DEBUG 338 Serial.println("discovered"); 339#endif 340 OPTConCharacteristic = peripheral.characteristic("f000aa72-0451-4000-b000-000000000000"); 341 OPTValCharacteristic = peripheral.characteristic("f000aa71-0451-4000-b000-000000000000"); 342 } 343 else { 344#ifdef DEBUG 345 Serial.println("Error: Luxometer service discovery failed."); 346#endif 347 peripheral.disconnect(); 348 return; 349 } 350 // IR 351#ifdef DEBUG 352 Serial.print("Discovering attributes for Infrared service ..."); 353#endif 354 if (peripheral.discoverService("f000aa00-0451-4000-b000-000000000000")) { 355#ifdef DEBUG 356 Serial.println("discovered"); 357#endif 358 IRTConCharacteristic = peripheral.characteristic("f000aa02-0451-4000-b000-000000000000"); 359 IRTValCharacteristic = peripheral.characteristic("f000aa01-0451-4000-b000-000000000000"); 360 } 361 else { 362#ifdef DEBUG 363 Serial.println("Error: Infrared service discovery failed."); 364#endif 365 peripheral.disconnect(); 366 return; 367 } 368 // humidity 369#ifdef DEBUG 370 Serial.print("Discovering attributes for Humidity service ..."); 371#endif 372 if (peripheral.discoverService("f000aa20-0451-4000-b000-000000000000")) { 373#ifdef DEBUG 374 Serial.println("discovered"); 375#endif 376 HUMConCharacteristic = peripheral.characteristic("f000aa22-0451-4000-b000-000000000000"); 377 HUMValCharacteristic = peripheral.characteristic("f000aa21-0451-4000-b000-000000000000"); 378 } 379 else { 380#ifdef DEBUG 381 Serial.println("Error: Humidity service discovery failed."); 382#endif 383 peripheral.disconnect(); 384 return; 385 } 386} 387 388// Sensor reads 389void read_BP(BLEDevice peripheral) { 390 uint8_t holdvalues[6]; 391 392 if (peripheral.connected()) { 393 // wake up the sensor 394 BPConCharacteristic.writeValue(sensorOn); 395 delay(1200); // wait for the sensor to do a read 396 BPValCharacteristic.readValue(holdvalues, 6); 397 unsigned long rawbptemp = (holdvalues[2] * 65536) + (holdvalues[1] * 256) + holdvalues[0]; 398 unsigned int rawbp = (holdvalues[5] * 65536) + (holdvalues[4] * 256) + holdvalues[3]; 399 // sleep sensor 400 BPConCharacteristic.writeValue(sensorOff); 401 // calculate temperature and pressure final values 402 float bptemp = ((double)rawbptemp / 100.0); 403 bptemp = ((bptemp * 9.0) / 5.0) + 32.0; // convert to F - comment out to leave at C 404 float bp = ((double)rawbp / 100.0); 405 // save into the structure 406 SensorData.bp = bp; 407 SensorData.bptemp = bptemp; 408 } 409 else { 410#ifdef DEBUG 411 Serial.println(" *not connected* "); 412#endif 413 } 414} 415 416void read_OPT(BLEDevice peripheral) { 417 // in this version the characteristic's value is read directly 418 // into rawlux and then processed. No array is used. 419 420 uint16_t rawlux; 421 422 if (peripheral.connected()) { 423 // wake up the sensor 424 OPTConCharacteristic.writeValue(sensorOn); 425 delay(1200); // wait for the sensor to do a read 426 OPTValCharacteristic.readValue(rawlux); 427 OPTConCharacteristic.writeValue(sensorOff); // sleep sensor 428 // calculate lux final value 429 unsigned int m = rawlux & 0x0FFF; 430 unsigned int e = (rawlux & 0xF000) >> 12; 431 float lux = (m * (0.01 * pow(2.0, e))); 432 // save into the structure 433 SensorData.li = lux; 434 } 435 else { 436#ifdef DEBUG 437 Serial.println(" *not connected* "); 438#endif 439 } 440} 441 442void read_IRT(BLEDevice peripheral) { 443 uint8_t holdvalues[4]; 444 445 if (peripheral.connected()) { 446 // wake up the sensor 447 IRTConCharacteristic.writeValue((uint8_t) 0x01); 448 delay(1200); // wait for the sensor to do a read 449 IRTValCharacteristic.readValue(holdvalues, 4); 450 unsigned int rawobj = (holdvalues[0]) + (holdvalues[1] * 256); 451 unsigned int rawamb = (holdvalues[2]) + (holdvalues[3] * 256); 452 IRTConCharacteristic.writeValue(sensorOff); // sleep sensor 453 // calculate final temperature values 454 const float SCALE_LSB = 0.03125; 455 int it = (int)( rawobj >> 2); 456 float IRTo = ( (float)it) * SCALE_LSB; 457 IRTo = ( (IRTo * 9.0) / 5.0 ) + 32.0; // convert to F - comment out to leave at C 458 it = (int)(rawamb >> 2); 459 float IRTa = (float)it * SCALE_LSB; 460 IRTa = ( (IRTa * 9.0) / 5.0) + 32.0; // convert to F - comment out to leave at C 461 // save into the structure 462 SensorData.temd = IRTa; 463 SensorData.temo = IRTo; 464 } 465 else { 466#ifdef DEBUG 467 Serial.println(" *not connected* "); 468#endif 469 } 470} 471 472void read_HUM(BLEDevice peripheral) { 473 uint8_t holdvalues[4]; // hold the characteristic's bytes 474 475 if (peripheral.connected()) { 476 // wake up sensor 477 HUMConCharacteristic.writeValue(sensorOn); 478 delay(1200); // wait for the sensor to do a read 479 HUMValCharacteristic.readValue(holdvalues, 4); 480 HUMConCharacteristic.writeValue(sensorOff); // sleep sensor 481 unsigned int rawtem = (holdvalues[0]) + (holdvalues[1] * 256); 482 unsigned int rawhum = (holdvalues[2]) + (holdvalues[3] * 256); 483 // calculate final temperature and relative humidity values 484 float temp = (rawtem / 65536.0) * 165.0 - 40.0; 485 temp = ((temp * 9.0) / 5.0) + 32.0; // convert to F - comment out to leave at C 486 float hum = ((double)rawhum / 65536.0) * 100.0; 487 // save into the structure 488 SensorData.tem = temp; 489 SensorData.hum = hum; 490 } 491 else { 492#ifdef DEBUG 493 Serial.println(" *not connected* "); 494#endif 495 } 496} 497 498// Print serial and screen and write SD routines 499void print_data() { 500 // Print the data to the serial moniter 501 // NOTE: the time vars could be slightly different then the SD card 502 // since they are two different routines but the Serial prints are 503 // mainly for debugging 504 505 String separator = ", "; 506 // Data Line as follow (with comma separator): 507 // epoch day, month, year, hours, minutes, seconds, HDC1000 temp, HDC1000 hum, 508 // BMP280 pressure, BMP280 tem, OPT3001 light (lux), TMP007 temp, TMP0007 object temp 509#ifdef DEBUG 510 Serial.print(rtc.getEpoch()); 511 Serial.print(separator); 512 Serial.print(rtc.getDay()); 513 Serial.print(separator); 514 Serial.print(rtc.getMonth()); 515 Serial.print(separator); 516 Serial.print(rtc.getYear()); 517 Serial.print(separator); 518 printP02D(rtc.getHours()); 519 Serial.print(separator); 520 printP02D(rtc.getMinutes()); 521 Serial.print(separator); 522 printP02D(rtc.getSeconds()); 523 Serial.print(separator); 524 Serial.print(SensorData.tem); 525 Serial.print(separator); 526 Serial.print(SensorData.hum); 527 Serial.print(separator); 528 Serial.print(SensorData.bp); 529 Serial.print(separator); 530 Serial.print(SensorData.bptemp); 531 Serial.print(separator); 532 Serial.print(SensorData.li); 533 Serial.print(separator); 534 Serial.print(SensorData.temo); 535 Serial.print(separator); 536 Serial.print(SensorData.temd); 537 Serial.println(); 538 // end of data line 539#endif 540} 541 542void write_SDdata() { 543 // Write the data to the SD card 544 String separator = ", "; 545 546 // Data Line as follow (with comma separator): 547 // epoch day, month, year, hours, minutes, seconds, HDC1000 temp, HDC1000 hum, 548 // BMP280 pressure, BMP280 tem, OPT3001 light (lux), TMP007 temp, TMP0007 object temp 549 // open the file 550 SDF = SD.open(fname, FILE_WRITE); 551 if (!SDF) { 552 // terminal error if we can't open the SD File (we already initialized) 553 u8x8.clearDisplay(); 554 u8x8.drawString(0, 2 , "SD Card "); 555 u8x8.drawString(0, 3 , "Terminal Error!"); 556#ifdef DEBUG 557 Serial.println("SD card write failure!"); 558#endif 559 while (1); 560 } 561 else { 562 // write the separator-delimited data line 563 // comment out what you don't want e.g., 564 // epoch, day,mon,year,hour,min,sec, HDC tem, HDC hum, AP, BMP tem, Illum, TMP obj Tem, TMP tem 565 SDF.print(rtc.getEpoch()); 566 SDF.print(separator); 567 SDF.print(rtc.getDay()); 568 SDF.print(separator); 569 SDF.print(rtc.getMonth()); 570 SDF.print(separator); 571 SDF.print(rtc.getYear()); 572 SDF.print(separator); 573 SDF.print(rtc.getHours()); 574 SDF.print(separator); 575 SDF.print(rtc.getMinutes()); 576 SDF.print(separator); 577 SDF.print(rtc.getSeconds()); 578 SDF.print(separator); 579 SDF.print(SensorData.tem); 580 SDF.print(separator); 581 SDF.print(SensorData.hum); 582 SDF.print(separator); 583 SDF.print(SensorData.bp); 584 SDF.print(separator); 585 SDF.print(SensorData.bptemp); 586 SDF.print(separator); 587 SDF.print(SensorData.li); 588 SDF.print(separator); 589 SDF.print(SensorData.temo); 590 SDF.print(separator); 591 SDF.print(SensorData.temd); 592 SDF.println(); // Windows cr/lf 593 SDF.close(); 594 } 595} 596 597void print_screenT() { 598 // print the LCD template 599 u8x8.setFont(u8x8_font_px437wyse700a_2x2_f); // large for Tem/Hum 600 u8x8.drawString(0, 0, "T:"); 601 u8x8.drawUTF8(14, 0, degree); 602 u8x8.drawString(0, 2, "H:"); 603 u8x8.drawUTF8(14, 2, percent); 604 // back to smaller font for tyhe rest 605 u8x8.setFont(u8x8_font_amstrad_cpc_extended_f); 606 u8x8.drawString(0, 5, "AP:"); 607 //u8x8.drawString(0, 5, "BP: 0123 hPa"); 608 u8x8.setCursor(10, 5); 609 u8x8.print(" hPa"); 610 u8x8.drawString(0, 6, "IL:"); 611 u8x8.setCursor(10, 6); 612 u8x8.print(" lux"); 613 // alternative times current left 614 u8x8.drawString(0, 7, "00:00"); 615 u8x8.drawString(11, 7, "00:00"); 616} 617 618void print_screenValues() { 619 float Dtem, Dhum, Dap, Dli; 620 // call this *after* sensor structure has been updated 621 // first update the logged time? need small font 622 u8x8.setFont(u8x8_font_px437wyse700a_2x2_f); // large for Tem/Hum 623 // temperature 624 // sensor error check NOTE: read values will be printed to screen and SD 625 Dtem = SensorData.tem; 626 if (Dtem > 999.9) Dtem = 999.9; 627 if (Dtem < -99.9) Dtem = -99.9; 628 dtostrf(Dtem, 5, 1, p_buffer); // convert to 5 chars 1 after decimal 629 u8x8.setCursor(4, 0); 630 u8x8.print(p_buffer); 631 //u8x8.drawUTF8(14, 0, degree); degree sign has been done in 632 // humidity 633 // sensor error check 634 Dhum = SensorData.hum; 635 if (Dhum > 100.0) Dhum = 100.0; 636 if (Dhum < 0.0) Dhum = 0.0; 637 dtostrf(Dhum, 5, 1, p_buffer); // convert to 5 chars 1 after decimal 638 u8x8.setCursor(4, 2); 639 u8x8.print(p_buffer); 640 //u8x8.drawUTF8(14, 2, percent); already done in template print 641 // back to smaller font for tyhe rest 642 u8x8.setFont(u8x8_font_amstrad_cpc_extended_f); 643 // barometric pressure 644 // sensor error check 645 Dap = SensorData.bp; 646 if (Dap < 750.0) Dap = 000.0; 647 if (Dap > 1200.0) Dap = 9999.9; 648 dtostrf(Dap, 7, 1, p_buffer); // convert to 7 chars 1 after decimal 649 u8x8.setCursor(3, 5); 650 u8x8.print(p_buffer); 651 // Illuminance 652 // sensor error check 653 Dli = SensorData.li; 654 if (Dli > 99999.9) Dli = 99999.9; 655 if (Dli < 0.0) Dli = 0; 656 dtostrf(Dli, 7, 1, p_buffer); // convert to 7 chars 1 after decimal 657 u8x8.setCursor(3, 6); 658 u8x8.print(p_buffer); 659} 660 661void printclockD(byte side) { 662 // print the HH:SS of the current clock on the right or left side of the LCD 663 // must be in a small font! (could do this as a switch case) 664int hourT,minT; 665 666 switch (side) { 667 case 1: //left side 668 u8x8.setCursor(0, 7); 669 hourT = rtc.getHours(); 670 if (hourT < 10) { // pad hours <10 671 u8x8.drawString(0, 7 , "0"); 672 u8x8.setCursor(1, 7); 673 u8x8.print(hourT); 674 } 675 else { 676 u8x8.print(hourT); 677 } 678 // note the ':' is from the template 679 u8x8.setCursor(3, 7); 680 minT = rtc.getMinutes(); 681 if (minT < 10) { // pad seconds <10 682 u8x8.drawString(3, 7 , "0"); 683 u8x8.setCursor(4, 7); 684 u8x8.print(minT); 685 } 686 else { 687 u8x8.print(minT); 688 } 689 break; 690 case 2: // right side 691 u8x8.setCursor(11, 7); 692 hourT = rtc.getHours(); 693 if (hourT < 10) { // pad hours <10 694 u8x8.drawString(11, 7 , "0"); 695 u8x8.setCursor(12, 7); 696 u8x8.print(hourT); 697 } 698 else { 699 u8x8.print(hourT); 700 } 701 // note the ':' is from the template 702 u8x8.setCursor(14, 7); 703 minT = rtc.getMinutes(); 704 if (minT < 10) { // pad secondss <10 705 u8x8.drawString(14, 7 , "0"); 706 u8x8.setCursor(15, 7); 707 u8x8.print(minT); 708 } 709 else { 710 u8x8.print(minT); 711 } 712 break; 713 default: // can add other options 714 // statements 715 break; 716 } 717} 718 719void printWiFiStatus() { 720 // note: this will only be called if DEBUG is defines 721 Serial.print("SSID: "); 722 Serial.println(WiFi.SSID()); 723 IPAddress ip = WiFi.localIP(); 724 Serial.print("IP Address: "); 725 Serial.println(ip); 726 long rssi = WiFi.RSSI(); 727 Serial.print("signal strength (RSSI):"); 728 Serial.print(rssi); 729 Serial.println(" dBm"); 730} 731 732void printP02D(int number) { 733 if (number < 10) Serial.print('0'); 734 Serial.print(number); 735} 736 737// End of code 738
Downloadable files
Wiring Diagram
Use these connections for either the NANO 33 IOT or MKR 1010 board to the SPI SD card module and the OLED LCD display.
Wiring Diagram
Wiring Diagram
Use these connections for either the NANO 33 IOT or MKR 1010 board to the SPI SD card module and the OLED LCD display.
Wiring Diagram
Comments
Only logged in users can leave comments