Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
Hand tools and fabrication machines | ||||||
| ||||||
|
Several years ago, I made a nice little data logger using the SensorTag from TI and an Arduino 101 to read and save the data using the BLE capabilities of the board. Alas, that board has gone away and I had been looking for a suitable replacement to take up the project once again.
Enter the MKR WiFi 1010 and Nano 33 IoT boards. Both of these boards have the needed BLE capability to connect to the SensorTag and much more.
In this project, I built a data logger capable of reading any of the sensors on the TI SensorTag, using just four components:
1) Either the MKR WiFi 1010 or the Nano 33 IoT board
2) SensorTag
3) SD card for saving the data
4) I2C OLED LCD module for viewing some of the data in real-time
Program Flow and Commentary:
Note the code and wiring is the same if you use either the Nano 33 IoT or the MKR WiFi 1010 in this project. Both boards have been tested in this project.
First the program checks that you have an SD card inserted and working. If not, an error will be displayed and execution goes no further. The project has been tested with the MicroSD click board as well as some generic SPI SD modules. If you do not want to use an SD card to save the data, you can eliminate that function by setting the value of a variable, see the program line,
byte SDswitch = 1; // SDswitch 1=ON (write to SD) or 0 (Do not write to SD)
By default, the option to write to the SD is on.
Next, the program will use the board's WiFi capability to contact a time server and get the current epoch. Note that you can correct this epoch for your time zone and DST setting (see program variable GMT). Once the epoch is obtained, the on-board real-time-clock (RTC) is set and used to keep the time.
Don't forget to add your own ssid and password for your internet connectivity, see program code lines:
char ssid[] = ""; // your network SSID (name)
char pass[] = ""; // your network password (use for WPA, or use as key for WEP)
The program requires that a time epoch is received so that accurate time stamping of the sensor reads can occur. After the time epoch has been received, WiFi is ended and BLE begins. Since both of the boards have WiFi and BLE capability, this is easily accomplished.
Next, the program scans for a SensorTag and attempts to connect when it is found. Note that there are different versions of the SensorTag CC2650 and some newer versions may not include the TMP007 sensor like mine does. In this case, you would simply need to comment out the program references to that sensor.
Currently, the program reads the following sensors:
HDC 1000 temperature F, HDC 1000 relative humidity %RH, BMP 280 temperature F, BMP 280 barometric pressure in hectoPascals, OPT3001 illumination in lux, TMP007 object temperature F and TMP007 temperature F
Data are saved on the SD card in comma-delimited format and consist of the following:
Epoch, day, month, year (last two digits), hours, minutes, seconds, followed by the sensor values in the order previously listed.
How frequently the sensors are read depends on a variable in the program - see the program line, long period = 600000L; The value (in milliseconds) defaults to every 10 minutes (plus sensor read time) but can be adjusted to whatever you like.
While the program is initializing, various progress messages will be displayed on the OLED LCD. Once the program has connected to the SensorTag and sensors are being read, some values will be continuously displayed and updated as follows.
From the top of the screen (see picture), Temperature and Humidity are displayed in a large font. Atmospheric pressure (AP) and Illumination (IL) are displayed on the next two lines. On the bottom line, the time (hh:mm) that the sensor was read is displayed on the left and on the right the current time is displayed (hh:min), which is updated every minute.
If you uncomment the program line,
//#define DEBUG // uncomment this line for serial monitor output
progress status when initializing and each sensor data line will be displayed on the serial monitor.
Libraries UsedThe program uses a number of libraries (listed below with the versions used) that must be installed. These libraries do all of the real work.
- WiFiNINA v1.40
- ArduinoBLE v1.1.1
- RTCZero 1.6.0
- SD v1.2.3
- U8g2 (U8x8) v2.26.14
The code was developed and tested using the Arduino IDE v1.8.10
This has been a fun and useful project. Both the Nano 33 IoT and MKR WiFi 1010, with their WiFi and BLE capabilities, along with the availability of some sophisticated libraries, made the project relatively easy to construct. Finally, only some of the available sensors on the SensorTag were used in the project, but it can be easily customized and expanded.
//*********************************************************************************
// YADL SensorTag Data Logger v1.0R [DrG]
// ** This software is offered strictly as is with no guarantees or warranties. **
// ** - USE IT AT YOUR OWN RISK! **
//*********************************************************************************
//
// Uses:
// WiFiNINA v1.40
// RTCZero 1.6.0
// ArduinoBLE v1.1.1
// SD v1.2.3
// U8g2 (U8x8) v2.26.14
//
// Arduino IDE v1.8.10
//
// Hardware:
// MKR1010 / NANO 33 IOT (both have been tested)
// microSD card (both generics and MicroElectronika click board tested)
// HiLetgo 1.3" I2C monochrome OLED (others should work with modification)
//
// Note: Replace the code entries below with your network info:
// char ssid[] = "XXXXXXXXXX";
// char pass[] = "XXXXXXXXXX";
//
// Note: set GMT (with DST if needed) in code entry:
// const int GMT =XX
//
// #includes
#include <WiFiNINA.h>
#include <RTCZero.h>
#include <ArduinoBLE.h>
#include <SPI.h>
#include <SD.h>
#include <U8x8lib.h>
#include <avr/dtostrf.h> // needed for MKR1010
//#define DEBUG // uncomment this line for serial monitor output
RTCZero rtc;
BLEDevice peripheral;
File SDF;
U8X8_SH1106_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE);
// Global structure to hold the sensor data
struct DATA {
float tem; // HDC1000 temperature F
float hum; // HDC1000 relative humidity %RH
float bptemp; // BMP 280 die temperature F
float bp; // BMP 280 barometric pressure in hectoPascals (1 hPa = 100 Pa)
float li; // OPT3001 lux
float temd; // TMP007 die temperature F
float temo; // TMP007 object temperature F
};
typedef struct DATA DATA;
DATA SensorData;
// for SensorTag sensors
uint8_t sensorOn = 1;
uint8_t sensorOff = 0;
// lcd vars
char degree[] = {0xb0, 0x00};
char percent[] = {0x25, 0x00};
char p_buffer[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// clock change catcher
int lastmin;
// for RTC
unsigned long epoch;
int numberOfTries = 0, maxTries = 6;
int status = WL_IDLE_STATUS; // WiFiNINA use
// Common user-changeable switches
const int GMT = -4; //change this to adapt it to your time zone
byte SDswitch = 1; // SDswitch 1=ON (write to SD) or 0 (Do not write to SD)
char fname[] = "STDATA.txt"; // data log file Name
//period defines the length of time between measurements in milliseconds
// note that this does not includes delays for sensor reads (~8.7 sec)
long period = 600000L; // 10 minutes
//long period = 5000L; // 5 sec for testing
char ssid[] = ""; // your network SSID (name)
char pass[] = ""; // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0; // your network key Index number (needed only for WEP)
// SensorTag characteristic definitions
// BMP280
BLECharacteristic BPConCharacteristic;
BLECharacteristic BPValCharacteristic;
// OPT3001
BLECharacteristic OPTConCharacteristic;
BLECharacteristic OPTValCharacteristic;
// TMP007
BLECharacteristic IRTConCharacteristic;
BLECharacteristic IRTValCharacteristic;
// HDC1000
BLECharacteristic HUMConCharacteristic;
BLECharacteristic HUMValCharacteristic;
//------------------------------------------------------------------
void setup() {
u8x8.begin(); // start lcd driver, will clear display
u8x8.setFont(u8x8_font_amstrad_cpc_extended_f); // 8 X 8 font
u8x8.drawString(0, 0, "YADL starting...");
#ifdef DEBUG
Serial.begin(9600);
delay(5000); // delay for user to open the serial monitor
Serial.println("YADL MKR1010/NANO IOT 33 SensorTag Data Logger");
Serial.println();
#endif
// check the SD card
if (SDswitch == 1) {
if (!SD.begin(4)) {
u8x8.drawString(0, 2 , "No SD card!");
u8x8.drawString(0, 3 , "Terminal Error!");
#ifdef DEBUG
Serial.println("SD Card initialization failed!");
#endif
while (1);
}
else {
u8x8.drawString(0, 2 , "SD card found. ");
delay(2000); // to let user know
u8x8.drawString(0, 2 , " ");
#ifdef DEBUG
Serial.println("SD Card found");
#endif
}
}
else {
u8x8.drawString(0, 2 , "No SD card");
u8x8.drawString(0, 3 , "option");
delay(2000); // to let user know
u8x8.drawString(0, 2 , " ");
u8x8.drawString(0, 3 , " ");
#ifdef DEBUG
Serial.println("No SD Card option");
#endif
}
delay(2000); // to let user know about sd card
// check if the WiFi module works
if (WiFi.status() == WL_NO_SHIELD) {
#ifdef DEBUG
Serial.println("WiFi shield not present");
#endif
u8x8.drawString(0, 1 , "NO WiFi!");
u8x8.drawString(0, 2 , "Terminal Error!");
// don't continue:
while (true);
}
// attempt to connect to WiFi network:
u8x8.drawString(0, 2 , "Connecting.....");
while ( status != WL_CONNECTED) {
#ifdef DEBUG
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
#endif
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(ssid, pass);
delay(10000); // wait 10 seconds for connection:
}
u8x8.drawString(0, 3 , "Connected! ");
#ifdef DEBUG
printWiFiStatus(); // you're connected now, so print out the status:
#endif
rtc.begin();
do {
epoch = WiFi.getTime();
numberOfTries++;
}
while ((epoch == 0) && (numberOfTries < maxTries));
if (numberOfTries == maxTries) {
u8x8.drawString(0, 4 , "NTP Unreachable");
u8x8.drawString(0, 5 , "TERMINAL ERROR!");
#ifdef DEBUG
Serial.print("NTP unreachable!!");
#endif
while (1);
}
else {
u8x8.drawString(0, 4 , "Got NTP Epoch ");
epoch = epoch + (GMT * 3600UL); // adjust offset for TZ/DST
rtc.setEpoch(epoch);
#ifdef DEBUG
Serial.print("Epoch received: ");
Serial.print(epoch);
Serial.print(" ");
printP02D(rtc.getHours());
Serial.print(":");
printP02D(rtc.getMinutes());
Serial.print(":");
printP02D(rtc.getSeconds());
Serial.print(" ");
Serial.print(rtc.getDay());
Serial.print("/");
Serial.print(rtc.getMonth());
Serial.print("/");
Serial.print(rtc.getYear());
Serial.println();
#endif
WiFi.end();
delay(15000);
u8x8.drawString(0, 5 , "WiFi Ended ");
u8x8.drawString(0, 6 , "Starting BLE ");
delay(2000); // to see it on the screen
#ifdef DEBUG
Serial.println("WiFi.end executed");
#endif
}
// Try to initialize BLE
if (!BLE.begin()) {
Serial.println("Terminal Error: Could not start BLE!");
u8x8.clear();
u8x8.drawString(0, 0 , "BLE Start Fail");
u8x8.drawString(0, 1 , "Terminal Error!");
while (1);
}
BLE.scan();
u8x8.clear();
u8x8.drawString(0, 0 , "Scanning......");
}
//------------------------------------------------------------------
void loop() {
long lastMillis = 0; // for period test
long nowMillis = 0; // for period test
// check if a peripheral has been discovered
peripheral = BLE.available();
if (peripheral) {
// discovered a peripheral, print out address and local name
#ifdef DEBUG
Serial.print("Found ");
Serial.print(peripheral.address());
Serial.print(" '");
Serial.print(peripheral.localName());
Serial.println("' ");
#endif
if (peripheral.localName() == "CC2650 SensorTag") {
BLE.stopScan(); // stop scanning
// connect to the peripheral
u8x8.drawString(0, 1 , "Connecting....");
#ifdef DEBUG
Serial.print("Connecting to SensorTag ...");
#endif
if (peripheral.connect()) {
u8x8.drawString(0, 2 , "Connected.....");
#ifdef DEBUG
Serial.println("Connected...");
#endif
do_discovery(peripheral);
// Note: we do not subscribe to any services because we are not using notify
u8x8.clear();
print_screenT();
#ifdef DEBUG
Serial.println("Reading sensors...");
Serial.println();
#endif
}
else {
u8x8.drawString(0, 2 , "Scanning......");
#ifdef DEBUG
Serial.println(" scanning");
#endif
}
}
// main while connected loop
while (peripheral.connected()) {
read_BP(peripheral);
read_OPT(peripheral);
read_IRT(peripheral);
read_HUM(peripheral);
if (SDswitch) write_SDdata(); // write data to sd card
// screen for debug no print here as well
#ifdef DEBUG
print_data();
#endif
print_screenValues();
printclockD(1); // Update sensor clock
printclockD(2); // update current clock
lastmin = rtc.getMinutes();
lastMillis = millis();
// stay here until the period is up
// update current time here
while ( ( (nowMillis = millis()) - lastMillis) <= period) {
// need to update the clock here
if (lastmin != rtc.getMinutes()) {
lastmin = rtc.getMinutes();
printclockD(2); // update current clock
}
}
}
// peripheral disconnected, start scanning again
u8x8.clear();
u8x8.drawString(0, 2 , "Scanning......");
#ifdef DEBUG
Serial.println(" - rescan...");
#endif
BLE.scan();
}
}
//------------------------------------------------------------------
// BLE SensorTag routines
void do_discovery(BLEDevice peripheral) {
// discover the peripheral's attributes that we want
// barometric
#ifdef DEBUG
Serial.print("Discovering attributes for Barometric Pressure service ...");
#endif
if (peripheral.discoverService("f000aa40-0451-4000-b000-000000000000")) {
#ifdef DEBUG
Serial.println("discovered");
#endif
BPConCharacteristic = peripheral.characteristic("f000aa42-0451-4000-b000-000000000000");
BPValCharacteristic = peripheral.characteristic("f000aa41-0451-4000-b000-000000000000");
}
else {
#ifdef DEBUG
Serial.println("ERROR: Barometric Pressure service discovery failed.");
#endif
peripheral.disconnect();
return;
}
// discover the peripheral's attributes that we want
// optical sensor
#ifdef DEBUG
Serial.print("Discovering attributes for Luxometer service ...");
#endif
if (peripheral.discoverService("f000aa70-0451-4000-b000-000000000000")) {
#ifdef DEBUG
Serial.println("discovered");
#endif
OPTConCharacteristic = peripheral.characteristic("f000aa72-0451-4000-b000-000000000000");
OPTValCharacteristic = peripheral.characteristic("f000aa71-0451-4000-b000-000000000000");
}
else {
#ifdef DEBUG
Serial.println("Error: Luxometer service discovery failed.");
#endif
peripheral.disconnect();
return;
}
// IR
#ifdef DEBUG
Serial.print("Discovering attributes for Infrared service ...");
#endif
if (peripheral.discoverService("f000aa00-0451-4000-b000-000000000000")) {
#ifdef DEBUG
Serial.println("discovered");
#endif
IRTConCharacteristic = peripheral.characteristic("f000aa02-0451-4000-b000-000000000000");
IRTValCharacteristic = peripheral.characteristic("f000aa01-0451-4000-b000-000000000000");
}
else {
#ifdef DEBUG
Serial.println("Error: Infrared service discovery failed.");
#endif
peripheral.disconnect();
return;
}
// humidity
#ifdef DEBUG
Serial.print("Discovering attributes for Humidity service ...");
#endif
if (peripheral.discoverService("f000aa20-0451-4000-b000-000000000000")) {
#ifdef DEBUG
Serial.println("discovered");
#endif
HUMConCharacteristic = peripheral.characteristic("f000aa22-0451-4000-b000-000000000000");
HUMValCharacteristic = peripheral.characteristic("f000aa21-0451-4000-b000-000000000000");
}
else {
#ifdef DEBUG
Serial.println("Error: Humidity service discovery failed.");
#endif
peripheral.disconnect();
return;
}
}
// Sensor reads
void read_BP(BLEDevice peripheral) {
uint8_t holdvalues[6];
if (peripheral.connected()) {
// wake up the sensor
BPConCharacteristic.writeValue(sensorOn);
delay(1200); // wait for the sensor to do a read
BPValCharacteristic.readValue(holdvalues, 6);
unsigned long rawbptemp = (holdvalues[2] * 65536) + (holdvalues[1] * 256) + holdvalues[0];
unsigned int rawbp = (holdvalues[5] * 65536) + (holdvalues[4] * 256) + holdvalues[3];
// sleep sensor
BPConCharacteristic.writeValue(sensorOff);
// calculate temperature and pressure final values
float bptemp = ((double)rawbptemp / 100.0);
bptemp = ((bptemp * 9.0) / 5.0) + 32.0; // convert to F - comment out to leave at C
float bp = ((double)rawbp / 100.0);
// save into the structure
SensorData.bp = bp;
SensorData.bptemp = bptemp;
}
else {
#ifdef DEBUG
Serial.println(" *not connected* ");
#endif
}
}
void read_OPT(BLEDevice peripheral) {
// in this version the characteristic's value is read directly
// into rawlux and then processed. No array is used.
uint16_t rawlux;
if (peripheral.connected()) {
// wake up the sensor
OPTConCharacteristic.writeValue(sensorOn);
delay(1200); // wait for the sensor to do a read
OPTValCharacteristic.readValue(rawlux);
OPTConCharacteristic.writeValue(sensorOff); // sleep sensor
// calculate lux final value
unsigned int m = rawlux & 0x0FFF;
unsigned int e = (rawlux & 0xF000) >> 12;
float lux = (m * (0.01 * pow(2.0, e)));
// save into the structure
SensorData.li = lux;
}
else {
#ifdef DEBUG
Serial.println(" *not connected* ");
#endif
}
}
void read_IRT(BLEDevice peripheral) {
uint8_t holdvalues[4];
if (peripheral.connected()) {
// wake up the sensor
IRTConCharacteristic.writeValue((uint8_t) 0x01);
delay(1200); // wait for the sensor to do a read
IRTValCharacteristic.readValue(holdvalues, 4);
unsigned int rawobj = (holdvalues[0]) + (holdvalues[1] * 256);
unsigned int rawamb = (holdvalues[2]) + (holdvalues[3] * 256);
IRTConCharacteristic.writeValue(sensorOff); // sleep sensor
// calculate final temperature values
const float SCALE_LSB = 0.03125;
int it = (int)( rawobj >> 2);
float IRTo = ( (float)it) * SCALE_LSB;
IRTo = ( (IRTo * 9.0) / 5.0 ) + 32.0; // convert to F - comment out to leave at C
it = (int)(rawamb >> 2);
float IRTa = (float)it * SCALE_LSB;
IRTa = ( (IRTa * 9.0) / 5.0) + 32.0; // convert to F - comment out to leave at C
// save into the structure
SensorData.temd = IRTa;
SensorData.temo = IRTo;
}
else {
#ifdef DEBUG
Serial.println(" *not connected* ");
#endif
}
}
void read_HUM(BLEDevice peripheral) {
uint8_t holdvalues[4]; // hold the characteristic's bytes
if (peripheral.connected()) {
// wake up sensor
HUMConCharacteristic.writeValue(sensorOn);
delay(1200); // wait for the sensor to do a read
HUMValCharacteristic.readValue(holdvalues, 4);
HUMConCharacteristic.writeValue(sensorOff); // sleep sensor
unsigned int rawtem = (holdvalues[0]) + (holdvalues[1] * 256);
unsigned int rawhum = (holdvalues[2]) + (holdvalues[3] * 256);
// calculate final temperature and relative humidity values
float temp = (rawtem / 65536.0) * 165.0 - 40.0;
temp = ((temp * 9.0) / 5.0) + 32.0; // convert to F - comment out to leave at C
float hum = ((double)rawhum / 65536.0) * 100.0;
// save into the structure
SensorData.tem = temp;
SensorData.hum = hum;
}
else {
#ifdef DEBUG
Serial.println(" *not connected* ");
#endif
}
}
// Print serial and screen and write SD routines
void print_data() {
// Print the data to the serial moniter
// NOTE: the time vars could be slightly different then the SD card
// since they are two different routines but the Serial prints are
// mainly for debugging
String separator = ", ";
// Data Line as follow (with comma separator):
// epoch day, month, year, hours, minutes, seconds, HDC1000 temp, HDC1000 hum,
// BMP280 pressure, BMP280 tem, OPT3001 light (lux), TMP007 temp, TMP0007 object temp
#ifdef DEBUG
Serial.print(rtc.getEpoch());
Serial.print(separator);
Serial.print(rtc.getDay());
Serial.print(separator);
Serial.print(rtc.getMonth());
Serial.print(separator);
Serial.print(rtc.getYear());
Serial.print(separator);
printP02D(rtc.getHours());
Serial.print(separator);
printP02D(rtc.getMinutes());
Serial.print(separator);
printP02D(rtc.getSeconds());
Serial.print(separator);
Serial.print(SensorData.tem);
Serial.print(separator);
Serial.print(SensorData.hum);
Serial.print(separator);
Serial.print(SensorData.bp);
Serial.print(separator);
Serial.print(SensorData.bptemp);
Serial.print(separator);
Serial.print(SensorData.li);
Serial.print(separator);
Serial.print(SensorData.temo);
Serial.print(separator);
Serial.print(SensorData.temd);
Serial.println();
// end of data line
#endif
}
void write_SDdata() {
// Write the data to the SD card
String separator = ", ";
// Data Line as follow (with comma separator):
// epoch day, month, year, hours, minutes, seconds, HDC1000 temp, HDC1000 hum,
// BMP280 pressure, BMP280 tem, OPT3001 light (lux), TMP007 temp, TMP0007 object temp
// open the file
SDF = SD.open(fname, FILE_WRITE);
if (!SDF) {
// terminal error if we can't open the SD File (we already initialized)
u8x8.clearDisplay();
u8x8.drawString(0, 2 , "SD Card ");
u8x8.drawString(0, 3 , "Terminal Error!");
#ifdef DEBUG
Serial.println("SD card write failure!");
#endif
while (1);
}
else {
// write the separator-delimited data line
// comment out what you don't want e.g.,
// epoch, day,mon,year,hour,min,sec, HDC tem, HDC hum, AP, BMP tem, Illum, TMP obj Tem, TMP tem
SDF.print(rtc.getEpoch());
SDF.print(separator);
SDF.print(rtc.getDay());
SDF.print(separator);
SDF.print(rtc.getMonth());
SDF.print(separator);
SDF.print(rtc.getYear());
SDF.print(separator);
SDF.print(rtc.getHours());
SDF.print(separator);
SDF.print(rtc.getMinutes());
SDF.print(separator);
SDF.print(rtc.getSeconds());
SDF.print(separator);
SDF.print(SensorData.tem);
SDF.print(separator);
SDF.print(SensorData.hum);
SDF.print(separator);
SDF.print(SensorData.bp);
SDF.print(separator);
SDF.print(SensorData.bptemp);
SDF.print(separator);
SDF.print(SensorData.li);
SDF.print(separator);
SDF.print(SensorData.temo);
SDF.print(separator);
SDF.print(SensorData.temd);
SDF.println(); // Windows cr/lf
SDF.close();
}
}
void print_screenT() {
// print the LCD template
u8x8.setFont(u8x8_font_px437wyse700a_2x2_f); // large for Tem/Hum
u8x8.drawString(0, 0, "T:");
u8x8.drawUTF8(14, 0, degree);
u8x8.drawString(0, 2, "H:");
u8x8.drawUTF8(14, 2, percent);
// back to smaller font for tyhe rest
u8x8.setFont(u8x8_font_amstrad_cpc_extended_f);
u8x8.drawString(0, 5, "AP:");
//u8x8.drawString(0, 5, "BP: 0123 hPa");
u8x8.setCursor(10, 5);
u8x8.print(" hPa");
u8x8.drawString(0, 6, "IL:");
u8x8.setCursor(10, 6);
u8x8.print(" lux");
// alternative times current left
u8x8.drawString(0, 7, "00:00");
u8x8.drawString(11, 7, "00:00");
}
void print_screenValues() {
float Dtem, Dhum, Dap, Dli;
// call this *after* sensor structure has been updated
// first update the logged time? need small font
u8x8.setFont(u8x8_font_px437wyse700a_2x2_f); // large for Tem/Hum
// temperature
// sensor error check NOTE: read values will be printed to screen and SD
Dtem = SensorData.tem;
if (Dtem > 999.9) Dtem = 999.9;
if (Dtem < -99.9) Dtem = -99.9;
dtostrf(Dtem, 5, 1, p_buffer); // convert to 5 chars 1 after decimal
u8x8.setCursor(4, 0);
u8x8.print(p_buffer);
//u8x8.drawUTF8(14, 0, degree); degree sign has been done in
// humidity
// sensor error check
Dhum = SensorData.hum;
if (Dhum > 100.0) Dhum = 100.0;
if (Dhum < 0.0) Dhum = 0.0;
dtostrf(Dhum, 5, 1, p_buffer); // convert to 5 chars 1 after decimal
u8x8.setCursor(4, 2);
u8x8.print(p_buffer);
//u8x8.drawUTF8(14, 2, percent); already done in template print
// back to smaller font for tyhe rest
u8x8.setFont(u8x8_font_amstrad_cpc_extended_f);
// barometric pressure
// sensor error check
Dap = SensorData.bp;
if (Dap < 750.0) Dap = 000.0;
if (Dap > 1200.0) Dap = 9999.9;
dtostrf(Dap, 7, 1, p_buffer); // convert to 7 chars 1 after decimal
u8x8.setCursor(3, 5);
u8x8.print(p_buffer);
// Illuminance
// sensor error check
Dli = SensorData.li;
if (Dli > 99999.9) Dli = 99999.9;
if (Dli < 0.0) Dli = 0;
dtostrf(Dli, 7, 1, p_buffer); // convert to 7 chars 1 after decimal
u8x8.setCursor(3, 6);
u8x8.print(p_buffer);
}
void printclockD(byte side) {
// print the HH:SS of the current clock on the right or left side of the LCD
// must be in a small font! (could do this as a switch case)
int hourT,minT;
switch (side) {
case 1: //left side
u8x8.setCursor(0, 7);
hourT = rtc.getHours();
if (hourT < 10) { // pad hours <10
u8x8.drawString(0, 7 , "0");
u8x8.setCursor(1, 7);
u8x8.print(hourT);
}
else {
u8x8.print(hourT);
}
// note the ':' is from the template
u8x8.setCursor(3, 7);
minT = rtc.getMinutes();
if (minT < 10) { // pad seconds <10
u8x8.drawString(3, 7 , "0");
u8x8.setCursor(4, 7);
u8x8.print(minT);
}
else {
u8x8.print(minT);
}
break;
case 2: // right side
u8x8.setCursor(11, 7);
hourT = rtc.getHours();
if (hourT < 10) { // pad hours <10
u8x8.drawString(11, 7 , "0");
u8x8.setCursor(12, 7);
u8x8.print(hourT);
}
else {
u8x8.print(hourT);
}
// note the ':' is from the template
u8x8.setCursor(14, 7);
minT = rtc.getMinutes();
if (minT < 10) { // pad secondss <10
u8x8.drawString(14, 7 , "0");
u8x8.setCursor(15, 7);
u8x8.print(minT);
}
else {
u8x8.print(minT);
}
break;
default: // can add other options
// statements
break;
}
}
void printWiFiStatus() {
// note: this will only be called if DEBUG is defines
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
}
void printP02D(int number) {
if (number < 10) Serial.print('0');
Serial.print(number);
}
// End of code
//*********************************************************************************
// YADL SensorTag Data Logger v1.0R [DrG]
// ** This software is offered strictly as is with no guarantees or warranties. **
// ** - USE IT AT YOUR OWN RISK! **
//*********************************************************************************
//
// Uses:
// WiFiNINA v1.40
// RTCZero 1.6.0
// ArduinoBLE v1.1.1
// SD v1.2.3
// U8g2 (U8x8) v2.26.14
//
// Arduino IDE v1.8.10
//
// Hardware:
// MKR1010 / NANO 33 IOT (both have been tested)
// microSD card (both generics and MicroElectronika click board tested)
// HiLetgo 1.3" I2C monochrome OLED (others should work with modification)
//
// Note: Replace the code entries below with your network info:
// char ssid[] = "XXXXXXXXXX";
// char pass[] = "XXXXXXXXXX";
//
// Note: set GMT (with DST if needed) in code entry:
// const int GMT =XX
//
// #includes
#include <WiFiNINA.h>
#include <RTCZero.h>
#include <ArduinoBLE.h>
#include <SPI.h>
#include <SD.h>
#include <U8x8lib.h>
#include <avr/dtostrf.h> // needed for MKR1010
//#define DEBUG // uncomment this line for serial monitor output
RTCZero rtc;
BLEDevice peripheral;
File SDF;
U8X8_SH1106_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE);
// Global structure to hold the sensor data
struct DATA {
float tem; // HDC1000 temperature F
float hum; // HDC1000 relative humidity %RH
float bptemp; // BMP 280 die temperature F
float bp; // BMP 280 barometric pressure in hectoPascals (1 hPa = 100 Pa)
float li; // OPT3001 lux
float temd; // TMP007 die temperature F
float temo; // TMP007 object temperature F
};
typedef struct DATA DATA;
DATA SensorData;
// for SensorTag sensors
uint8_t sensorOn = 1;
uint8_t sensorOff = 0;
// lcd vars
char degree[] = {0xb0, 0x00};
char percent[] = {0x25, 0x00};
char p_buffer[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// clock change catcher
int lastmin;
// for RTC
unsigned long epoch;
int numberOfTries = 0, maxTries = 6;
int status = WL_IDLE_STATUS; // WiFiNINA use
// Common user-changeable switches
const int GMT = -2; //change this to adapt it to your time zone
byte SDswitch = 1; // SDswitch 1=ON (write to SD) or 0 (Do not write to SD)
char fname[] = "STDATA.txt"; // data log file Name
//period defines the length of time between measurements in milliseconds
// note that this does not includes delays for sensor reads (~8.7 sec)
long period = 600000L; // 10 minutes
//long period = 5000L; // 5 sec for testing
char ssid[] = ""; // your network SSID (name)
char pass[] = ""; // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0; // your network key Index number (needed only for WEP)
// SensorTag characteristic definitions
// BMP280
BLECharacteristic BPConCharacteristic;
BLECharacteristic BPValCharacteristic;
// OPT3001
BLECharacteristic OPTConCharacteristic;
BLECharacteristic OPTValCharacteristic;
// TMP007
BLECharacteristic IRTConCharacteristic;
BLECharacteristic IRTValCharacteristic;
// HDC1000
BLECharacteristic HUMConCharacteristic;
BLECharacteristic HUMValCharacteristic;
//------------------------------------------------------------------
void setup() {
u8x8.begin(); // start lcd driver, will clear display
u8x8.setFont(u8x8_font_amstrad_cpc_extended_f); // 8 X 8 font
u8x8.drawString(0, 0, "YADL starting...");
#ifdef DEBUG
Serial.begin(9600);
delay(5000); // delay for user to open the serial monitor
Serial.println("YADL MKR1010/NANO IOT 33 SensorTag Data Logger");
Serial.println();
#endif
// check the SD card
if (SDswitch == 1) {
if (!SD.begin(4)) {
u8x8.drawString(0, 2 , "No SD card!");
u8x8.drawString(0, 3 , "Terminal Error!");
#ifdef DEBUG
Serial.println("SD Card initialization failed!");
#endif
while (1);
}
else {
u8x8.drawString(0, 2 , "SD card found. ");
delay(2000); // to let user know
u8x8.drawString(0, 2 , " ");
#ifdef DEBUG
Serial.println("SD Card found");
#endif
}
}
else {
u8x8.drawString(0, 2 , "No SD card");
u8x8.drawString(0, 3 , "option");
delay(2000); // to let user know
u8x8.drawString(0, 2 , " ");
u8x8.drawString(0, 3 , " ");
#ifdef DEBUG
Serial.println("No SD Card option");
#endif
}
delay(2000); // to let user know about sd card
// check if the WiFi module works
if (WiFi.status() == WL_NO_SHIELD) {
#ifdef DEBUG
Serial.println("WiFi shield not present");
#endif
u8x8.drawString(0, 1 , "NO WiFi!");
u8x8.drawString(0, 2 , "Terminal Error!");
// don't continue:
while (true);
}
// attempt to connect to WiFi network:
u8x8.drawString(0, 2 , "Connecting.....");
while ( status != WL_CONNECTED) {
#ifdef DEBUG
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
#endif
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(ssid, pass);
delay(10000); // wait 10 seconds for connection:
}
u8x8.drawString(0, 3 , "Connected! ");
#ifdef DEBUG
printWiFiStatus(); // you're connected now, so print out the status:
#endif
rtc.begin();
do {
epoch = WiFi.getTime();
numberOfTries++;
}
while ((epoch == 0) && (numberOfTries < maxTries));
if (numberOfTries == maxTries) {
u8x8.drawString(0, 4 , "NTP Unreachable");
u8x8.drawString(0, 5 , "TERMINAL ERROR!");
#ifdef DEBUG
Serial.print("NTP unreachable!!");
#endif
while (1);
}
else {
u8x8.drawString(0, 4 , "Got NTP Epoch ");
epoch = epoch + (GMT * 3600UL); // adjust offset for TZ/DST
rtc.setEpoch(epoch);
#ifdef DEBUG
Serial.print("Epoch received: ");
Serial.print(epoch);
Serial.print(" ");
printP02D(rtc.getHours());
Serial.print(":");
printP02D(rtc.getMinutes());
Serial.print(":");
printP02D(rtc.getSeconds());
Serial.print(" ");
Serial.print(rtc.getDay());
Serial.print("/");
Serial.print(rtc.getMonth());
Serial.print("/");
Serial.print(rtc.getYear());
Serial.println();
#endif
WiFi.end();
delay(15000);
u8x8.drawString(0, 5 , "WiFi Ended ");
u8x8.drawString(0, 6 , "Starting BLE ");
delay(2000); // to see it on the screen
#ifdef DEBUG
Serial.println("WiFi.end executed");
#endif
}
// Try to initialize BLE
if (!BLE.begin()) {
Serial.println("Terminal Error: Could not start BLE!");
u8x8.clear();
u8x8.drawString(0, 0 , "BLE Start Fail");
u8x8.drawString(0, 1 , "Terminal Error!");
while (1);
}
BLE.scan();
u8x8.clear();
u8x8.drawString(0, 0 , "Scanning......");
}
//------------------------------------------------------------------
void loop() {
long lastMillis = 0; // for period test
long nowMillis = 0; // for period test
// check if a peripheral has been discovered
peripheral = BLE.available();
if (peripheral) {
// discovered a peripheral, print out address and local name
#ifdef DEBUG
Serial.print("Found ");
Serial.print(peripheral.address());
Serial.print(" '");
Serial.print(peripheral.localName());
Serial.println("' ");
#endif
if (peripheral.localName() == "CC2650 SensorTag") {
BLE.stopScan(); // stop scanning
// connect to the peripheral
u8x8.drawString(0, 1 , "Connecting....");
#ifdef DEBUG
Serial.print("Connecting to SensorTag ...");
#endif
if (peripheral.connect()) {
u8x8.drawString(0, 2 , "Connected.....");
#ifdef DEBUG
Serial.println("Connected...");
#endif
do_discovery(peripheral);
// Note: we do not subscribe to any services because we are not using notify
u8x8.clear();
print_screenT();
#ifdef DEBUG
Serial.println("Reading sensors...");
Serial.println();
#endif
}
else {
u8x8.drawString(0, 2 , "Scanning......");
#ifdef DEBUG
Serial.println(" scanning");
#endif
}
}
// main while connected loop
while (peripheral.connected()) {
read_BP(peripheral);
read_OPT(peripheral);
read_IRT(peripheral);
read_HUM(peripheral);
if (SDswitch) write_SDdata(); // write data to sd card
// screen for debug no print here as well
#ifdef DEBUG
print_data();
#endif
print_screenValues();
printclockD(1); // Update sensor clock
printclockD(2); // update current clock
lastmin = rtc.getMinutes();
lastMillis = millis();
// stay here until the period is up
// update current time here
while ( ( (nowMillis = millis()) - lastMillis) <= period) {
// need to update the clock here
if (lastmin != rtc.getMinutes()) {
lastmin = rtc.getMinutes();
printclockD(2); // update current clock
}
}
}
// peripheral disconnected, start scanning again
u8x8.clear();
u8x8.drawString(0, 2 , "Scanning......");
#ifdef DEBUG
Serial.println(" - rescan...");
#endif
BLE.scan();
}
}
//------------------------------------------------------------------
// BLE SensorTag routines
void do_discovery(BLEDevice peripheral) {
// discover the peripheral's attributes that we want
// barometric
#ifdef DEBUG
Serial.print("Discovering attributes for Barometric Pressure service ...");
#endif
if (peripheral.discoverService("f000aa40-0451-4000-b000-000000000000")) {
#ifdef DEBUG
Serial.println("discovered");
#endif
BPConCharacteristic = peripheral.characteristic("f000aa42-0451-4000-b000-000000000000");
BPValCharacteristic = peripheral.characteristic("f000aa41-0451-4000-b000-000000000000");
}
else {
#ifdef DEBUG
Serial.println("ERROR: Barometric Pressure service discovery failed.");
#endif
peripheral.disconnect();
return;
}
// discover the peripheral's attributes that we want
// optical sensor
#ifdef DEBUG
Serial.print("Discovering attributes for Luxometer service ...");
#endif
if (peripheral.discoverService("f000aa70-0451-4000-b000-000000000000")) {
#ifdef DEBUG
Serial.println("discovered");
#endif
OPTConCharacteristic = peripheral.characteristic("f000aa72-0451-4000-b000-000000000000");
OPTValCharacteristic = peripheral.characteristic("f000aa71-0451-4000-b000-000000000000");
}
else {
#ifdef DEBUG
Serial.println("Error: Luxometer service discovery failed.");
#endif
peripheral.disconnect();
return;
}
// IR
#ifdef DEBUG
Serial.print("Discovering attributes for Infrared service ...");
#endif
if (peripheral.discoverService("f000aa00-0451-4000-b000-000000000000")) {
#ifdef DEBUG
Serial.println("discovered");
#endif
IRTConCharacteristic = peripheral.characteristic("f000aa02-0451-4000-b000-000000000000");
IRTValCharacteristic = peripheral.characteristic("f000aa01-0451-4000-b000-000000000000");
}
else {
#ifdef DEBUG
Serial.println("Error: Infrared service discovery failed.");
#endif
peripheral.disconnect();
return;
}
// humidity
#ifdef DEBUG
Serial.print("Discovering attributes for Humidity service ...");
#endif
if (peripheral.discoverService("f000aa20-0451-4000-b000-000000000000")) {
#ifdef DEBUG
Serial.println("discovered");
#endif
HUMConCharacteristic = peripheral.characteristic("f000aa22-0451-4000-b000-000000000000");
HUMValCharacteristic = peripheral.characteristic("f000aa21-0451-4000-b000-000000000000");
}
else {
#ifdef DEBUG
Serial.println("Error: Humidity service discovery failed.");
#endif
peripheral.disconnect();
return;
}
}
// Sensor reads
void read_BP(BLEDevice peripheral) {
uint8_t holdvalues[6];
if (peripheral.connected()) {
// wake up the sensor
BPConCharacteristic.writeValue(sensorOn);
delay(1200); // wait for the sensor to do a read
BPValCharacteristic.readValue(holdvalues, 6);
unsigned long rawbptemp = (holdvalues[2] * 65536) + (holdvalues[1] * 256) + holdvalues[0];
unsigned int rawbp = (holdvalues[5] * 65536) + (holdvalues[4] * 256) + holdvalues[3];
// sleep sensor
BPConCharacteristic.writeValue(sensorOff);
// calculate temperature and pressure final values
float bptemp = ((double)rawbptemp / 100.0);
bptemp = ((bptemp * 9.0) / 5.0) + 32.0; // convert to F - comment out to leave at C
float bp = ((double)rawbp / 100.0);
// save into the structure
SensorData.bp = bp;
SensorData.bptemp = bptemp;
}
else {
#ifdef DEBUG
Serial.println(" *not connected* ");
#endif
}
}
void read_OPT(BLEDevice peripheral) {
// for this sensor the characteristic's value is read directly
// into rawlux and then processed. No array is used.
uint16_t rawlux;
if (peripheral.connected()) {
// wake up the sensor
OPTConCharacteristic.writeValue(sensorOn);
delay(1200); // wait for the sensor to do a read
OPTValCharacteristic.readValue(rawlux);
OPTConCharacteristic.writeValue(sensorOff); // sleep sensor
// calculate lux final value
unsigned int m = rawlux & 0x0FFF;
unsigned int e = (rawlux & 0xF000) >> 12;
float lux = (m * (0.01 * pow(2.0, e)));
// save into the structure
SensorData.li = lux;
}
else {
#ifdef DEBUG
Serial.println(" *not connected* ");
#endif
}
}
void read_IRT(BLEDevice peripheral) {
uint8_t holdvalues[4];
if (peripheral.connected()) {
// wake up the sensor
IRTConCharacteristic.writeValue((uint8_t) 0x01);
delay(1200); // wait for the sensor to do a read
IRTValCharacteristic.readValue(holdvalues, 4);
unsigned int rawobj = (holdvalues[0]) + (holdvalues[1] * 256);
unsigned int rawamb = (holdvalues[2]) + (holdvalues[3] * 256);
IRTConCharacteristic.writeValue(sensorOff); // sleep sensor
// calculate final temperature values
const float SCALE_LSB = 0.03125;
int it = (int)( rawobj >> 2);
float IRTo = ( (float)it) * SCALE_LSB;
IRTo = ( (IRTo * 9.0) / 5.0 ) + 32.0; // convert to F - comment out to leave at C
it = (int)(rawamb >> 2);
float IRTa = (float)it * SCALE_LSB;
IRTa = ( (IRTa * 9.0) / 5.0) + 32.0; // convert to F - comment out to leave at C
// save into the structure
SensorData.temd = IRTa;
SensorData.temo = IRTo;
}
else {
#ifdef DEBUG
Serial.println(" *not connected* ");
#endif
}
}
void read_HUM(BLEDevice peripheral) {
uint8_t holdvalues[4]; // hold the characteristic's bytes
if (peripheral.connected()) {
// wake up sensor
HUMConCharacteristic.writeValue(sensorOn);
delay(1200); // wait for the sensor to do a read
HUMValCharacteristic.readValue(holdvalues, 4);
HUMConCharacteristic.writeValue(sensorOff); // sleep sensor
unsigned int rawtem = (holdvalues[0]) + (holdvalues[1] * 256);
unsigned int rawhum = (holdvalues[2]) + (holdvalues[3] * 256);
// calculate final temperature and relative humidity values
float temp = (rawtem / 65536.0) * 165.0 - 40.0;
temp = ((temp * 9.0) / 5.0) + 32.0; // convert to F - comment out to leave at C
float hum = ((double)rawhum / 65536.0) * 100.0;
// save into the structure
SensorData.tem = temp;
SensorData.hum = hum;
}
else {
#ifdef DEBUG
Serial.println(" *not connected* ");
#endif
}
}
// Print serial and screen and write SD routines
void print_data() {
// Print the data to the serial moniter
// NOTE: the time vars could be slightly different than the SD card
// since they are two different routines but the Serial prints are
// mainly for debugging
String separator = ", ";
// Data Line as follow (with comma separator):
// epoch day, month, year, hours, minutes, seconds, HDC1000 temp, HDC1000 hum,
// BMP280 pressure, BMP280 tem, OPT3001 light (lux), TMP007 object temp, TMP007 temp
#ifdef DEBUG
Serial.print(rtc.getEpoch());
Serial.print(separator);
Serial.print(rtc.getDay());
Serial.print(separator);
Serial.print(rtc.getMonth());
Serial.print(separator);
Serial.print(rtc.getYear());
Serial.print(separator);
printP02D(rtc.getHours());
Serial.print(separator);
printP02D(rtc.getMinutes());
Serial.print(separator);
printP02D(rtc.getSeconds());
Serial.print(separator);
Serial.print(SensorData.tem);
Serial.print(separator);
Serial.print(SensorData.hum);
Serial.print(separator);
Serial.print(SensorData.bp);
Serial.print(separator);
Serial.print(SensorData.bptemp);
Serial.print(separator);
Serial.print(SensorData.li);
Serial.print(separator);
Serial.print(SensorData.temo);
Serial.print(separator);
Serial.print(SensorData.temd);
Serial.println();
// end of data line
#endif
}
void write_SDdata() {
// Write the data to the SD card
String separator = ", ";
// Data Line as follow (with comma separator):
// epoch day, month, year, hours, minutes, seconds, HDC1000 temp, HDC1000 hum,
// BMP280 pressure, BMP280 tem, OPT3001 light (lux), TMP007 temp, TMP0007 object temp
// open the file
SDF = SD.open(fname, FILE_WRITE);
if (!SDF) {
// terminal error if we can't open the SD File (we already initialized)
u8x8.clearDisplay();
u8x8.drawString(0, 2 , "SD Card ");
u8x8.drawString(0, 3 , "Terminal Error!");
#ifdef DEBUG
Serial.println("SD card write failure!");
#endif
while (1);
}
else {
// write the separator-delimited data line
// comment out what you don't want e.g.,
// epoch, day,mon,year,hour,min,sec, HDC tem, HDC hum, AP, BMP tem, Illum, TMP obj Tem, TMP tem
SDF.print(rtc.getEpoch());
SDF.print(separator);
SDF.print(rtc.getDay());
SDF.print(separator);
SDF.print(rtc.getMonth());
SDF.print(separator);
SDF.print(rtc.getYear());
SDF.print(separator);
SDF.print(rtc.getHours());
SDF.print(separator);
SDF.print(rtc.getMinutes());
SDF.print(separator);
SDF.print(rtc.getSeconds());
SDF.print(separator);
SDF.print(SensorData.tem);
SDF.print(separator);
SDF.print(SensorData.hum);
SDF.print(separator);
SDF.print(SensorData.bp);
SDF.print(separator);
SDF.print(SensorData.bptemp);
SDF.print(separator);
SDF.print(SensorData.li);
SDF.print(separator);
SDF.print(SensorData.temo);
SDF.print(separator);
SDF.print(SensorData.temd);
SDF.println(); // Windows cr/lf
SDF.close();
}
}
void print_screenT() {
// print the LCD template
u8x8.setFont(u8x8_font_px437wyse700a_2x2_f); // large for Tem/Hum
u8x8.drawString(0, 0, "T:");
u8x8.drawUTF8(14, 0, degree);
u8x8.drawString(0, 2, "H:");
u8x8.drawUTF8(14, 2, percent);
// back to smaller font for tyhe rest
u8x8.setFont(u8x8_font_amstrad_cpc_extended_f);
u8x8.drawString(0, 5, "AP:");
//u8x8.drawString(0, 5, "BP: 0123 hPa");
u8x8.setCursor(10, 5);
u8x8.print(" hPa");
u8x8.drawString(0, 6, "IL:");
u8x8.setCursor(10, 6);
u8x8.print(" lux");
// alternative times current left
u8x8.drawString(0, 7, "00:00");
u8x8.drawString(11, 7, "00:00");
}
void print_screenValues() {
float Dtem, Dhum, Dap, Dli;
// call this *after* sensor structure has been updated
// first update the logged time? need small font
u8x8.setFont(u8x8_font_px437wyse700a_2x2_f); // large for Tem/Hum
// temperature
// sensor error check NOTE: read values will be printed to screen and SD
Dtem = SensorData.tem;
if (Dtem > 999.9) Dtem = 999.9;
if (Dtem < -99.9) Dtem = -99.9;
dtostrf(Dtem, 5, 1, p_buffer); // convert to 5 chars 1 after decimal
u8x8.setCursor(4, 0);
u8x8.print(p_buffer);
//u8x8.drawUTF8(14, 0, degree); degree sign has been done in
// humidity
// sensor error check
Dhum = SensorData.hum;
if (Dhum > 100.0) Dhum = 100.0;
if (Dhum < 0.0) Dhum = 0.0;
dtostrf(Dhum, 5, 1, p_buffer); // convert to 5 chars 1 after decimal
u8x8.setCursor(4, 2);
u8x8.print(p_buffer);
//u8x8.drawUTF8(14, 2, percent); already done in template print
// back to smaller font for tyhe rest
u8x8.setFont(u8x8_font_amstrad_cpc_extended_f);
// barometric pressure
// sensor error check
Dap = SensorData.bp;
if (Dap < 750.0) Dap = 000.0;
if (Dap > 1200.0) Dap = 9999.9;
dtostrf(Dap, 7, 1, p_buffer); // convert to 7 chars 1 after decimal
u8x8.setCursor(3, 5);
u8x8.print(p_buffer);
// Illuminance
// sensor error check
Dli = SensorData.li;
if (Dli > 99999.9) Dli = 99999.9;
if (Dli < 0.0) Dli = 0;
dtostrf(Dli, 7, 1, p_buffer); // convert to 7 chars 1 after decimal
u8x8.setCursor(3, 6);
u8x8.print(p_buffer);
}
void printclockD(byte side) {
// print the HH:SS of the current clock on the right or left side of the LCD
// must be in a small font! (could do this as a switch case)
int hourT,minT;
switch (side) {
case 1: //left side
u8x8.setCursor(0, 7);
hourT = rtc.getHours();
if (hourT < 10) { // pad hours <10
u8x8.drawString(0, 7 , "0");
u8x8.setCursor(1, 7);
u8x8.print(hourT);
}
else {
u8x8.print(hourT);
}
// note the ':' is from the template
u8x8.setCursor(3, 7);
minT = rtc.getMinutes();
if (minT < 10) { // pad seconds <10
u8x8.drawString(3, 7 , "0");
u8x8.setCursor(4, 7);
u8x8.print(minT);
}
else {
u8x8.print(minT);
}
break;
case 2: // right side
u8x8.setCursor(11, 7);
hourT = rtc.getHours();
if (hourT < 10) { // pad hours <10
u8x8.drawString(11, 7 , "0");
u8x8.setCursor(12, 7);
u8x8.print(hourT);
}
else {
u8x8.print(hourT);
}
// note the ':' is from the template
u8x8.setCursor(14, 7);
minT = rtc.getMinutes();
if (minT < 10) { // pad secondss <10
u8x8.drawString(14, 7 , "0");
u8x8.setCursor(15, 7);
u8x8.print(minT);
}
else {
u8x8.print(minT);
}
break;
default: // can add other options
// statements
break;
}
}
void printWiFiStatus() {
// note: this will only be called if DEBUG is defines
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
}
void printP02D(int number) {
if (number < 10) Serial.print('0');
Serial.print(number);
}
// End of code
Comments