Code: Select all
/***************************************************
Lung Healing Technologies
****************************************************/
#include "SdFat.h"
#include "sdios.h"
#include "wiring_private.h" // pinPeripheral() function
#include <Adafruit_GFX.h> // Core graphics library
#include <SPI.h>
#include <Adafruit_ILI9341.h>
#include "TouchScreen.h"
#include "RTClib.h"
#include <SoftwareSerial.h>
#include "Adafruit_LC709203F.h"
//#include "FreeStack.h"
//#include "Adafruit_TinyUSB.h"
//#include <HardwareSerial.h>
//#include "Adafruit_SPIFlash.h"
#include <Adafruit_BME280.h>
#include "WiFi.h"
#include <HTTPClient.h>
#include "time.h"
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = -21600;
const int daylightOffset_sec = 3600;
// WiFi credentials
String ssid= " "; // change SSID
String password= " "; // change password
// Google script ID and required credentials
String GOOGLE_SCRIPT_ID = "AKfycbzAu28AnDyVypdPQB9Vbu-ISFYzalXyFqjq52YRj3q5plZwJmrdiNEayyo4IUvwr6sClA"; // change Gscript ID
int count = 0;
Adafruit_BME280 bme; // use I2C interface
Adafruit_LC709203F lc;
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 0
/*
Change the value of SD_CS_PIN if you are using SPI and
your hardware does not use the default value, SS.
Common values are:
Arduino Ethernet shield: pin 4
Sparkfun SD shield: pin 8
Adafruit SD shields and modules: pin 10
*/
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
/*#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SS;
#else // SDCARD_SS_PIN
// Assume built-in SD is used.
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif // SDCARD_SS_PIN*/
//i did
const uint8_t SD_CS_PIN = 5;
// Try max SPI clock for an SD. Reduce SPI_CLOCK if errors occur.
#define SPI_CLOCK SD_SCK_MHZ(16) //was 50
// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
#else // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
#endif // HAS_SDIO_CLASS
/*
#if SD_FAT_TYPE == 0
SdFat sd;
File file;
#elif SD_FAT_TYPE == 1
SdFat32 sd;
File32 file;
#elif SD_FAT_TYPE == 2
SdExFat sd;
ExFile file;
#elif SD_FAT_TYPE == 3
SdFs sd;
FsFile file;
#else // SD_FAT_TYPE
#error Invalid SD_FAT_TYPE
#endif // SD_FAT_TYPE*/
#if SD_FAT_TYPE == 0
SdFat sd;
File dir;
File file;
#elif SD_FAT_TYPE == 1
SdFat32 sd;
File32 dir;
File32 file;
#elif SD_FAT_TYPE == 2
SdExFat sd;
ExFile dir;
ExFile file;
#elif SD_FAT_TYPE == 3
SdFs sd;
FsFile dir;
FsFile file;
#else // SD_FAT_TYPE
#error invalid SD_FAT_TYPE
#endif // SD_FAT_TYPE
// Serial output stream
ArduinoOutStream cout(Serial);
#define MYPORT_TX A2 //12
#define MYPORT_RX A3 //13
SoftwareSerial myPort;
RTC_PCF8523 rtc;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
// These are the four touchscreen analog pins
#define YP A4 // must be an analog pin, use "An" notation!
#define XM A5 // must be an analog pin, use "An" notation!
#define YM 10 // can be any digital pin
#define XP 9 // can be any digital pin
// This is calibration data for the raw touch data to the screen coordinates
/*From V2, but they look off:
#define TS_MINX 150
#define TS_MINY 120
#define TS_MAXX 920
#define TS_MAXY 940*/
#define TS_MINX 0
#define TS_MINY -100
#define TS_MAXX 840
#define TS_MAXY 880
#define MINPRESSURE 10
#define MAXPRESSURE 1000
#define RECORDS 300
#define PRESSURE_DIFFERENCE -1.6 // External - internal
// The display uses hardware SPI, plus #11 & #10
#define TFT_CS 6
#define TFT_DC 11
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// For better pressure precision, we need to know the resistance
// between X+ and X- Use any multimeter to read it
// For the one we're using, its 300 ohms across the X plate
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
const int ledPin = 13; // the number of the LED pin
int ledState = HIGH;
int sdflag = 1;
float co2[RECORDS];
float o2[RECORDS];
float temperature[RECORDS];
float pressure[RECORDS];
float volts[RECORDS];
float batt_percent[RECORDS];
DateTime timestamps[RECORDS];
float co2_minutes[RECORDS];
float o2_minutes[RECORDS];
float temperature_minutes[RECORDS];
float pressure_minutes[RECORDS];
float volts_minutes[RECORDS];
float batt_percent_minutes[RECORDS];
DateTime timestamps_minutes[RECORDS];
int stamps=0;
float co2ambient = 0.04;
float o2ambient = 20.5;
float co2high = 0.4;
float co2low = 0.04;
float o2high = 21.5;
float o2low = 18.0;
int graphy = 0;
int graphy_minutes = 0;
float o2offset = 0.0;
//int toggle = 0;
int writeposition = 0;
int writeposition_minutes = 0;
int screen = 0;
int NotAmbientColor = ILI9341_YELLOW;
int minutecount = 0;
float lowvolts = 3.9;
float lowbatt_percent = 30;
float lowpressure = -20.0;
int newpatientflag = 0;
long patientnumber = 0;
char rawfilename [20] = "\0";
char minutefilename [20] = "\0";
// Size of the color selection boxes and the paintbrush size
#define BOXSIZE 40
#define BANNED 3
int oldcolor, currentcolor;
/************************************************Early code*********************/
void testdrawtext(char *text, uint16_t color) {
tft.setRotation(3);
tft.setCursor(0, 100);
tft.setTextColor(color);
tft.setTextWrap(true);
tft.setTextSize(4);
tft.print(text);
}
/************************************************Setup*********************/
void setup(void) {
Serial.begin(9600);
/* while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}*/
myPort.begin(9600, SWSERIAL_8N1, MYPORT_RX, MYPORT_TX, false);
if (!myPort) { // If the object did not initialize, then its configuration is invalid
Serial.println("Invalid SoftwareSerial pin configuration, check config");
while (1) { // Don't continue with invalid configuration
delay (1000);
}
}
else {Serial.println("myPort looks good");}
Serial1.begin (9600);
pinMode(TFT_CS, OUTPUT);
pinMode(SD_CS_PIN, OUTPUT);
// Set all chip selects high to avoid bus contention during initialisation of each peripheral
// digitalWrite(22, HIGH); // Touch controller chip select (if used)
digitalWrite(TFT_CS, HIGH); // TFT screen chip select
digitalWrite(SD_CS_PIN, HIGH); // SD card chips select
uint16_t time = millis();
tft.begin();
tft.fillScreen(ILI9341_BLACK);
time = millis() - time;
Serial.println(time, DEC);
delay(500);
// large block of text
tft.fillScreen(ILI9341_BLACK);
// testdrawtext("Lung Healing Technologies", ILI9341_WHITE);
tft.setRotation(2);
tft.setCursor(0, 0);
tft.setTextColor(ILI9341_WHITE);
tft.setTextWrap(true);
tft.setTextSize(3);
tft.print("Lung Healing Technologies");
tft.setCursor(0, 160);
tft.setTextColor(ILI9341_CYAN);
tft.setTextWrap(true);
tft.setTextSize(3);
tft.println("New Patient?");
tft.setTextSize(2);
tft.println("Press Y or N with");
tft.print("your fingernail");
// tft.fillRect(0, 303, 100, 16, ILI9341_RED);
tft.fillRect(0, 280, 100, 39, ILI9341_RED);
tft.setTextSize(3);
tft.setTextColor(ILI9341_BLACK);
tft.setCursor(10, 284);
tft.print("YES");
tft.fillRect(139, 280, 100, 39, ILI9341_GREEN);
tft.setTextSize(3);
tft.setTextColor(ILI9341_BLACK);
tft.setCursor(149, 284);
tft.print("NO");
while(newpatientflag == 0)
{
// Retrieve a point
analogReadResolution(10);
TSPoint p = ts.getPoint();
/* Serial.print("X = "); Serial.print(p.x);
Serial.print("\tY = "); Serial.print(p.y);
Serial.print("\tPressure = "); Serial.println(p.z); */
// Scale from ~0->1000 to tft.width using the calibration #'s
p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());
/* Serial.print("("); Serial.print(p.x);
Serial.print(", "); Serial.print(p.y);
Serial.println(")");*/
// we have some minimum pressure we consider 'valid'
// pressure of 0 means no pressing!
if (p.z > MINPRESSURE && p.z < MAXPRESSURE)
{
if (p.x>140 && p.x<239 && p.y>0 && p.y<39)
{
tft.fillRect(0, 280, 100, 39, ILI9341_BLACK);
tft.setTextSize(3);
tft.setTextColor(ILI9341_RED);
tft.setCursor(10, 284);
tft.print("YES");
newpatientflag=1;
Serial.print("Pressed at...");
Serial.print("("); Serial.print(p.x);
Serial.print(", "); Serial.print(p.y);
Serial.println(")");
}
else if (p.x>0 && p.x<100 && p.y>0 && p.y<39)
{
tft.fillRect(139, 280, 100, 39, ILI9341_BLACK);
tft.setTextSize(3);
tft.setTextColor(ILI9341_GREEN);
tft.setCursor(149, 284);
tft.print("NO");
newpatientflag=2;
Serial.print("Pressed at...");
Serial.print("("); Serial.print(p.x);
Serial.print(", "); Serial.print(p.y);
Serial.println(")");
}
}
}
delay(500);
tft.fillScreen(ILI9341_BLACK);
tft.setTextSize(3);
tft.setTextColor(ILI9341_WHITE);
tft.setCursor(0, 0);
tft.println("Booting...");
tft.setTextSize(1);
if(newpatientflag == 1) {tft.println("New patient selected");}
if(newpatientflag == 2) {tft.println("Not a new patient");}
// For the Feather ESP32-S2, we need to enable I2C power first!
// this section can be deleted for other boards
#if defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S2)
// turn on the I2C power by setting pin to opposite of 'rest state'
pinMode(PIN_I2C_POWER, INPUT);
delay(1);
bool polarity = digitalRead(PIN_I2C_POWER);
pinMode(PIN_I2C_POWER, OUTPUT);
digitalWrite(PIN_I2C_POWER, !polarity);
#endif
if (!lc.begin())
{
Serial.println(F("Couldnt find Adafruit LC709203F?\nMake sure a battery is plugged in!"));
tft.setTextColor(ILI9341_RED);
tft.println("Could not find battery!");
delay(2000);
}
else
{
Serial.println(F("Found LC709203F"));
Serial.print("Version: 0x"); Serial.println(lc.getICversion(), HEX);
tft.println("Found battery");
}
lc.setThermistorB(3950);
Serial.print("Thermistor B = "); Serial.println(lc.getThermistorB());
lc.setPackSize(LC709203F_APA_2000MAH);
lc.setAlarmVoltage(3.8);
//Clock
if (! rtc.begin())
{
Serial.println("Couldn't find RTC!");
Serial.flush();
tft.setTextColor(ILI9341_RED);
tft.println("Could not find Real Time Clock!");
delay(2000);
// while (1) delay(10);
}
else
{
Serial.println("Found RTC");
tft.println("Found Real Time Clock");
}
if (! rtc.initialized() || rtc.lostPower()) {
Serial.println("RTC is NOT initialized, let's set the time!");
// When time needs to be set on a new device, or after a power loss, the
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
//
// Note: allow 2 seconds after inserting battery or applying external power
// without battery before calling adjust(). This gives the PCF8523's
// crystal oscillator time to stabilize. If you call adjust() very quickly
// after the RTC is powered, lostPower() may still return true.
}
// When time needs to be re-set on a previously configured device, the
// following line sets the RTC to the date & time this sketch was compiled
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
// When the RTC was stopped and stays connected to the battery, it has
// to be restarted by clearing the STOP bit. Let's do this to ensure
// the RTC is running.
rtc.start();
// The PCF8523 can be calibrated for:
// - Aging adjustment
// - Temperature compensation
// - Accuracy tuning
// The offset mode to use, once every two hours or once every minute.
// The offset Offset value from -64 to +63. See the Application Note for calculation of offset values.
// https://www.nxp.com/docs/en/application-note/AN11247.pdf
// The deviation in parts per million can be calculated over a period of observation. Both the drift (which can be negative)
// and the observation period must be in seconds. For accuracy the variation should be observed over about 1 week.
// Note: any previous calibration should cancelled prior to any new observation period.
// Example - RTC gaining 43 seconds in 1 week
float drift = 43; // seconds plus or minus over oservation period - set to 0 to cancel previous calibration.
float period_sec = (7 * 86400); // total obsevation period in seconds (86400 = seconds in 1 day: 7 days = (7 * 86400) seconds )
float deviation_ppm = (drift / period_sec * 1000000); // deviation in parts per million (μs)
float drift_unit = 4.34; // use with offset mode PCF8523_TwoHours
// float drift_unit = 4.069; //For corrections every min the drift_unit is 4.069 ppm (use with offset mode PCF8523_OneMinute)
int offset = round(deviation_ppm / drift_unit);
// rtc.calibrate(PCF8523_TwoHours, offset); // Un-comment to perform calibration once drift (seconds) and observation period (seconds) are correct
// rtc.calibrate(PCF8523_TwoHours, 0); // Un-comment to cancel previous calibration
Serial.print("Offset is "); Serial.println(offset); // Print to control offset
char dt[16];
char tm[16];
DateTime now = rtc.now();
sprintf(dt, "%02d/%02d/%02d", now.year(),now.month(),now.day());
sprintf(tm, "%02d:%02d:%02d", now.hour(),now.minute(),now.second());
Serial.print("Date/Time is ");
Serial.print(dt);
Serial.print(" ");
Serial.println(tm);
tft.print("Date/Time is ");
tft.print(dt);
tft.print(" ");
tft.println(tm);
//Done clock
//Start pressure sensor
if (!bme.begin())
{
Serial.println(F("Could not find a valid BME280 sensor, check wiring!"));
tft.setTextColor(ILI9341_RED);
tft.println("Could not find external pressure sensor BME280!");
delay(2000);
// while (1) delay(10);
}
else
{
Serial.println("Found BME280 sensor");
tft.println("Found external pressure sensor");
}
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
tft.println("Putting O2 sensor into Poll Mode");
Serial.print("Putting O2 sensor into Poll Mode...");
Serial1.print("M 1\r\n"); // put O2 into Poll mode
delay(50);
Serial.print(Serial1.readString());
tft.println("Putting CO2 sensor into Poll Mode");
Serial.print("Putting CO2 sensor into Poll Mode...");
myPort.print("K 2\r\n"); // put CO2 into Poll mode
delay(50);
Serial.print(myPort.readString());
tft.print("Opening SD drive and connecting to wifi ");
//Uncomment the below to recalibrate CO2 sensor to 400ppm
/* Serial.print("Resetting CO2...");
Serial2.print("G\r\n");
delay(50);
Serial.print(Serial2.readString());*/
//Uncomment the below to recalibrate CO2 sensor to a specific value
/*For example, to set the zero point in a COZIR‐A when the sensor is in a known gas concentration of
2000ppm
send: X 2000\r\n
response: X 32950\r\n*/
//Uncomment the below to let CO2 sensor autocalibrate (and turn off with : To disable auto-zero, send @ 0\r\n)
/* Serial.print("Autocalibrate CO2...");
Serial2.print("@ #\r\n"); // "@ 0.3 0.3\r\n"
delay(50);
Serial.print(Serial2.readString());*/
cout << F("\nUse a freshly formatted SD for best performance.\n");
if (!ENABLE_DEDICATED_SPI)
{
cout << F(
"\nSet ENABLE_DEDICATED_SPI nonzero in\n"
"SdFatConfig.h for best SPI performance.\n");
}
#if HAS_UNUSED_STACK
cout << F("FreeStack: ") << FreeStack() << endl;
#endif // HAS_UNUSED_STACK
// pinMode(6, OUTPUT);
digitalWrite(TFT_CS, HIGH);
digitalWrite(SD_CS_PIN, LOW);
if (!sd.begin(SD_CONFIG))
{
// sd.initErrorHalt(&Serial);
Serial.print("SD card failed to initialize!...");
sdflag=2;
}
else
{
Serial.print("SD card initialized...");
sdflag=0;
}
if (sd.fatType() == FAT_TYPE_EXFAT) {
cout << F("Type is exFAT") << endl;
} else {
cout << F("Type is FAT") << int(sd.fatType()) << endl;
}
cout << F("Card size: ") << sd.card()->sectorCount()*512E-9;
cout << F(" GB (GB = 1E9 bytes)") << endl;
long freeKB = sd.vol()->freeClusterCount();
// freeKB *= sd.vol()->blocksPerCluster()/2;
freeKB *= sd.vol()->sectorsPerCluster()/2;
Serial.print("Free space KB: ");
Serial.println(freeKB);
patientnumber = now.unixtime();
Serial.print("Unix time, initial new patient number is: ");
Serial.println(patientnumber);
char tmpfilename [20] = "\0";
int ffbreak = 0;ffbreak++;
long tmppatientnumber = 0;
if(newpatientflag==2) //1 is Yes, 2 is No
{
// Open root directory
if (!dir.open("/"))
{
Serial.println("dir.open failed");
}
// Open next file in root.
// Warning, openNext starts at the current position of dir so a
// rewind may be necessary in your application.
while (file.openNext(&dir, O_RDONLY))
{
file.printFileSize(&Serial);
Serial.write(' ');
file.printModifyDateTime(&Serial);
Serial.write(' ');
file.printName(&Serial);
if (file.isDir())
{
// Indicate a directory.
Serial.write('/');
}
Serial.println();
char linen[20];
file.getName(linen, 20);
char linen2[20];
*linen2 = '\0';
strncat(linen2, linen, 10);
if(atoi(linen2)>tmppatientnumber)
{
tmppatientnumber=atoi(linen2);
}
file.close();
}
if (dir.getError())
{
Serial.println("openNext failed");
}
else
{
Serial.println("Done!");
}
patientnumber=tmppatientnumber;
Serial.print("tmpfilename at end is: ");
Serial.println(tmpfilename);
}
//Find wifi credentials
if (!sd.exists("/admin"))
{
Serial.println("Admin directory not found, creating...");
// Use mkdir to create directory (note you should _not_ have a trailing slash).
sd.mkdir("/admin");
}
else
{
Serial.println("Admin directory exists");
}
if (!sd.exists("/admin/settings.txt"))
{
Serial.println("settings.txt not found!");
}
else
{
Serial.println("settings.txt found, opening");
}
if(!file.open("/admin/settings.txt", O_READ)){Serial.println("Could not open settings.txt!");}
String line = file.readStringUntil('\n');
Serial.print("First line: "); Serial.println(line);
ssid = line.substring(line.indexOf('\"')+1, line.lastIndexOf('\"'));
//fline.toCharArray(ssid, fline.length() + 1); //ssid = fline;
// Serial.print("ssid fline: "); Serial.println(fline);
Serial.print("ssid: "); Serial.println(ssid);
String line2 = file.readStringUntil('\n');
Serial.print("Second line: "); Serial.println(line2);
password = line2.substring(line2.indexOf('\"')+1, line2.lastIndexOf('\"'));
//fline.toCharArray(password, fline.length() + 1);
Serial.print("password: "); Serial.println(password);
file.close();
// connect to WiFi
Serial.println();
Serial.print("Connecting to wifi...");
Serial.println(ssid);
Serial.flush();
tft.print("ssid ");
tft.print(ssid);
tft.print("...");
// WiFi.begin(ssid, password);
WiFi.begin(ssid.c_str(), password.c_str());
int wificount = 0;
while (WiFi.status() != WL_CONNECTED && wificount < 10)
{
tft.print(".");
Serial.print("Not connected yet!");
Serial.print("...");
Serial.print(wificount);
delay(500);
Serial.print("...");
Serial.println("Trying again...");
wificount++;
}
int yr = 0;
int mt = 0;
int dy = 0;
int hr = 0;
int mi = 0;
int se = 0;
if (WiFi.status() == WL_CONNECTED)
{
Serial.println("Connected to Wifi");
tft.println("Connected");
// Init and get the time
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
struct tm timeinfo;
getLocalTime(&timeinfo);
yr = timeinfo.tm_year + 1900;
mt = timeinfo.tm_mon + 1;
dy = timeinfo.tm_mday;
hr = timeinfo.tm_hour;
mi = timeinfo.tm_min;
se = timeinfo.tm_sec;
Serial.print("network time is ");
Serial.print(yr);
Serial.print("/");
Serial.print(mt);
Serial.print("/");
Serial.print(dy);
Serial.print(" ");
Serial.print(hr);
Serial.print(":");
Serial.print(mi);
Serial.print(":");
Serial.println(se);
if(yr>2022)
{
rtc.adjust(DateTime(yr, mt, dy, hr, mi, se));
tft.println("Updated the time from the network");
Serial.println("Updated the time from the network");
}
else
{
tft.setTextColor(ILI9341_YELLOW);
tft.println("Did not update time from the network!");
Serial.println("Did not update time from the network!");
}
}
else
{
Serial.println("Failed to connect to WiFi!");
tft.setTextColor(ILI9341_RED);
tft.println("Failed!");
delay(2000);
}
// digitalWrite(TFT_CS, LOW);
// digitalWrite(SD_CS_PIN, HIGH);
if (newpatientflag==2)
{
if (patientnumber!=tmppatientnumber)
{
tft.setTextColor(ILI9341_RED);
tft.println("Did not find previous patient file!");
}
else
{
tft.println("Found previous patient file");
}
}
sprintf(rawfilename + strlen(rawfilename), "%s","/");
sprintf(rawfilename + strlen(rawfilename), "%ld",patientnumber);
sprintf(rawfilename + strlen(rawfilename), "%s","raw.csv");
tft.print("Free space on SD card is ");
tft.print(freeKB);
tft.println(" KB");
if (freeKB==0)
{
tft.setTextColor(ILI9341_RED);
tft.println("Check that the SD card is insterted");
}
if (freeKB<1000000)
{
tft.setTextColor(ILI9341_RED);
tft.println("Delete some files on the SD card");
}
tft.print("Patient number is ");
tft.println(patientnumber);
tft.setTextSize(2);
tft.setCursor(0, 300);
tft.print("Starting...");
delay(500);
tft.println(".");
delay(500);
tft.println(".");
delay(500);
tft.println(".");
delay(500);
/*//Activate this code to pause the screen at boot
tft.fillRect(40, 280, 160, 39, ILI9341_GREEN);
tft.setTextSize(2);
tft.setTextColor(ILI9341_BLACK);
tft.setCursor(60, 284);
tft.print("PRESS START");
int letsgo = 0;
while(letsgo == 0)
{
// Retrieve a point
analogReadResolution(10);
TSPoint p = ts.getPoint();
// Scale from ~0->1000 to tft.width using the calibration #'s
p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());
// we have some minimum pressure we consider 'valid'
// pressure of 0 means no pressing!
if (p.z > MINPRESSURE && p.z < MAXPRESSURE)
{
if (p.x>40 && p.x<200 && p.y>0 && p.y<39)
{
tft.fillRect(40, 280, 160, 39, ILI9341_YELLOW);
tft.setTextSize(3);
tft.setTextColor(ILI9341_BLACK);
tft.setCursor(50, 284);
tft.print("STARTING");
letsgo=1;
Serial.print("Pressed at...");
Serial.print("("); Serial.print(p.x);
Serial.print(", "); Serial.print(p.y);
Serial.println(")");
}
}
}
delay(200);*/
}
/***************************************************LOOP*******/
void loop() {
char dataString[120] = "\0"; // make a string for assembling the data to log
String dataStringo = "";
String dataStringco = "";
String tmp = "";
int co2ppm = 0;
int touched = 0;
/* float co2total = 0;
float temperaturetotal = 0;
float pressuretotal = 0;*/
char dataString_minutes[100] = "\0"; // make a string for assembling the data to log - minutes
int SensorAttempts = 10;
int scount = 0;
/*first record is always the most recent*/
for (int counter = RECORDS - 1; counter > 0; counter--) {
o2[counter]=o2[counter-1];
co2[counter]=co2[counter-1];
pressure[counter]=pressure[counter-1];
temperature[counter]=temperature[counter-1];
timestamps[counter]=timestamps[counter-1];
volts[counter]=volts[counter-1];
batt_percent[counter]=batt_percent[counter-1];
}
sprintf(dataString, "%ld", patientnumber);
sprintf(dataString + strlen(dataString), "%s",",");
timestamps[0] = rtc.now();
sprintf(dataString + strlen(dataString), "%02d", timestamps[0].month());
sprintf(dataString + strlen(dataString), "%s","/");
sprintf(dataString + strlen(dataString), "%02d", timestamps[0].day());
sprintf(dataString + strlen(dataString), "%s","/");
sprintf(dataString + strlen(dataString), "%02d ",timestamps[0].year());
sprintf(dataString + strlen(dataString), "%02d",timestamps[0].hour());
sprintf(dataString + strlen(dataString), "%s",":");
sprintf(dataString + strlen(dataString), "%02d",timestamps[0].minute());
sprintf(dataString + strlen(dataString), "%s",":");
sprintf(dataString + strlen(dataString), "%02d",timestamps[0].second());
//Turn on LED while polling sensors
digitalWrite(ledPin, HIGH);
Serial.print("Poll O2 Sensor...");
Serial1.print("A\r\n"); // Poll sensor
delay(50);
dataStringo = (Serial1.readString());
Serial.print(dataStringo);
tmp = dataStringo.substring(26, 33);
Serial.print(tmp);
o2[0] = o2offset+tmp.toFloat();
tmp = dataStringo.substring(12, 17);
Serial.print(tmp);
temperature[0] = tmp.toFloat();
tmp = dataStringo.substring(19, 24);
Serial.print(tmp);
pressure[0] = tmp.toFloat()-(bme.readPressure() / 100.0F)-PRESSURE_DIFFERENCE;
sprintf(dataString + strlen(dataString), "%s",",");
sprintf(dataString + strlen(dataString), "%.2f", o2[0]);
sprintf(dataString + strlen(dataString), "%s",",");
sprintf(dataString + strlen(dataString), "%.1f", temperature[0]);
sprintf(dataString + strlen(dataString), "%s",",");
sprintf(dataString + strlen(dataString), "%.0f", pressure[0]);
scount = 0;
while (scount < SensorAttempts) {
Serial.print("Poll CO2 Sensor...");
Serial.print(scount);
Serial.print("...");
myPort.print("Z\r\n"); // Poll sensor
delay(50);
dataStringco = (myPort.readString());
Serial.print(dataStringco);
if (dataStringco.indexOf('Z')==-1)
{scount++;}
else
{scount=SensorAttempts;}
}
if (dataStringco.indexOf('Z')==-1){Serial.println("CO2 sensor did not repond!");}
dataStringco.replace("Z", "0");
dataStringco.remove(0, 2);
co2ppm = dataStringco.toFloat();
co2[0] = co2ppm/1000.0;
sprintf(dataString + strlen(dataString), "%s",",");
sprintf(dataString + strlen(dataString), "%.3f",co2[0]);
digitalWrite(ledPin, LOW);//Finish polling sensors, and turn LED off
// read external pressure
Serial.print("External Pressure = ");
Serial.print(bme.readPressure() / 100.0F);
Serial.println(" hPa");
// read battery voltage:
volts[0] = lc.cellVoltage();
batt_percent[0] = lc.cellPercent();
Serial.print("Battery voltage and percent...");
Serial.println(volts[0]);
sprintf(dataString + strlen(dataString), "%s",",");
sprintf(dataString + strlen(dataString), "%.2f",volts[0]);
sprintf(dataString + strlen(dataString), "%s",",");
sprintf(dataString + strlen(dataString), "%.1f",batt_percent[0]);
Serial.println(dataString);
Serial.print("Batt_Voltage:");
Serial.print(volts[0], 3);
Serial.print("\t");
Serial.print("Batt_Percent:");
Serial.print(batt_percent[0], 1);
Serial.print("\t");
Serial.print("Batt_Temp:");
Serial.println(lc.getCellTemperature(), 1);
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
// open or create file - truncate existing file.
if (!sd.exists(rawfilename))
{
Serial.print(rawfilename);
Serial.println(" not found! creating and opening...");
}
else
{
Serial.print(rawfilename);
Serial.println(" exists, opening");
}
if(!file.open(rawfilename, O_RDWR | O_CREAT | O_APPEND))
{
Serial.println("Could not open raw.txt!");
sdflag=3;
}
else
{
sdflag=0;
}
// Once open for writing you can print to the file as if you're printing
// to the serial terminal, the same functions are available.
file.println(dataString);
Serial.println("Wrote to file raw.txt!");
Serial.print("Total size of raw.txt (bytes): "); Serial.println(file.size(), DEC);
writeposition = file.position();
// Close the file when finished writing.
file.close();
/* Now aggregate by minute*/
if (graphy>0)
{
if (timestamps[0].minute() != timestamps[1].minute())
{
sprintf(dataString_minutes, "%02d", timestamps[0].month());
sprintf(dataString_minutes + strlen(dataString_minutes), "%s","/");
sprintf(dataString_minutes + strlen(dataString_minutes), "%02d", timestamps_minutes[0].day());
sprintf(dataString_minutes + strlen(dataString_minutes), "%s","/");
sprintf(dataString_minutes + strlen(dataString_minutes), "%02d ",timestamps_minutes[0].year());
sprintf(dataString_minutes + strlen(dataString_minutes), "%02d",timestamps_minutes[0].hour());
sprintf(dataString_minutes + strlen(dataString_minutes), "%s",":");
sprintf(dataString_minutes + strlen(dataString_minutes), "%02d",timestamps_minutes[0].minute());
sprintf(dataString_minutes + strlen(dataString_minutes), "%s",":00");
sprintf(dataString_minutes + strlen(dataString_minutes), "%s",",");
sprintf(dataString_minutes + strlen(dataString_minutes), "%.2f", o2_minutes[0]);
sprintf(dataString_minutes + strlen(dataString_minutes), "%s",",");
sprintf(dataString_minutes + strlen(dataString_minutes), "%.1f", temperature_minutes[0]);
sprintf(dataString_minutes + strlen(dataString_minutes), "%s",",");
sprintf(dataString_minutes + strlen(dataString_minutes), "%.0f", pressure_minutes[0]);
sprintf(dataString_minutes + strlen(dataString_minutes), "%s",",");
sprintf(dataString_minutes + strlen(dataString_minutes), "%.3f",co2_minutes[0]);
sprintf(dataString_minutes + strlen(dataString_minutes), "%s",",");
sprintf(dataString_minutes + strlen(dataString_minutes), "%.2f",volts_minutes[0]);
sprintf(dataString_minutes + strlen(dataString_minutes), "%s",",");
sprintf(dataString_minutes + strlen(dataString_minutes), "%.2f",batt_percent_minutes[0]);
Serial.println(dataString_minutes);
/*first record is always the most recent*/
for (int counter = RECORDS - 1; counter > 0; counter--) {co2_minutes[counter]=co2_minutes[counter-1];}
for (int counter = RECORDS - 1; counter > 0; counter--) {o2_minutes[counter]=o2_minutes[counter-1];}
for (int counter = RECORDS - 1; counter > 0; counter--) {pressure_minutes[counter]=pressure_minutes[counter-1];}
for (int counter = RECORDS - 1; counter > 0; counter--) {temperature_minutes[counter]=temperature_minutes[counter-1];}
for (int counter = RECORDS - 1; counter > 0; counter--) {volts_minutes[counter]=volts_minutes[counter-1];}
for (int counter = RECORDS - 1; counter > 0; counter--) {batt_percent_minutes[counter]=batt_percent_minutes[counter-1];}
for (int counter = RECORDS - 1; counter > 0; counter--) {timestamps_minutes[counter]=timestamps_minutes[counter-1];}
// Serial.print("co2 avg = "); Serial.println(co2_minutes[0]);
minutecount = 0;
co2_minutes[0]= 0;
o2_minutes[0]= 0;
pressure_minutes[0]= 0;
temperature_minutes[0]= 0;
volts_minutes[0]= 0;
batt_percent_minutes[0]= 0;
if(graphy_minutes<240){graphy_minutes++;}
}
}
co2_minutes[0]=(co2_minutes[0]*minutecount+ co2[0])/(minutecount+1);
o2_minutes[0]=(o2_minutes[0]*minutecount+ o2[0])/(minutecount+1);
pressure_minutes[0]=(pressure_minutes[0]*minutecount+ pressure[0])/(minutecount+1);
temperature_minutes[0]=(temperature_minutes[0]*minutecount+ temperature[0])/(minutecount+1);
volts_minutes[0]=(volts_minutes[0]*minutecount+ volts[0])/(minutecount+1);
batt_percent_minutes[0]=(batt_percent_minutes[0]*minutecount+ batt_percent[0])/(minutecount+1);
timestamps_minutes[0] = timestamps[0];
minutecount = minutecount + 1;
// Retrieve a point
touched = 0;
int touchcount=0;
TSPoint p = ts.getPoint();
while (touched==0 && touchcount<5)
{
analogReadResolution(10);
p = ts.getPoint();
/* Serial.print("X = "); Serial.print(p.x);
Serial.print("\tY = "); Serial.print(p.y);*/
Serial.print("\tPressure = "); Serial.println(p.z);
// we have some minimum pressure we consider 'valid'
// pressure of 0 means no pressing!
if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {touched = 1;}
touchcount++;
delay (10);
}
// Scale from ~0->1000 to tft.width using the calibration #'s
p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());
Serial.print("("); Serial.print(p.x);
Serial.print(", "); Serial.print(p.y);
Serial.println(")");
// tft.fillRect(257, 17, 50, 16, ILI9341_CYAN);
Serial.print("touched");Serial.println(touched);
Serial.print("screen");Serial.println(screen);
if (graphy==0)
{
tft.fillScreen(ILI9341_BLACK);
mainscreenbackground();
}
if (touched == 1)
{
if (screen == 2)
{
screen = 0;
tft.fillScreen(ILI9341_BLACK);
mainscreenbackground();
}
else
{
screen = screen+1;
tft.fillScreen(ILI9341_BLACK);
detailbackground();
}
}
if (screen == 0) {mainscreen();}
else if (screen == 1)
{detailscreen(graphy, timestamps, co2, o2, temperature, pressure);}
else if (screen == 2)
{detailscreen(graphy_minutes, timestamps_minutes, co2_minutes, o2_minutes, temperature_minutes, pressure_minutes);}
if (WiFi.status() == WL_CONNECTED) {
// static bool flag = false;
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain network time!");
return;
}
char timeStringBuff[50]; //50 chars should be enough
strftime(timeStringBuff, sizeof(timeStringBuff), "%A, %B %d %Y %H:%M:%S", &timeinfo);
String asString(timeStringBuff);
asString.replace(" ", "-");
Serial.print("Time:");
Serial.println(asString);
// String urlFinal = "https://script.google.com/macros/s/"+GOOGLE_SCRIPT_ID+"/exec?"+ "&sensor=" + String(count) +"date=" + asString ;
// String urlFinal = "https://script.google.com/macros/s/AKfycbwOfdaq2-hyrhu7Nhi52ts_qXUf8_bfOUp7jGkDT_Ga2b4Phn7rZmLZMka9bJayGUVIrA/exec?sensor=36&date=1103";
// https://script.google.com/macros/s/AKfycbwOfdaq2-hyrhu7Nhi52ts_qXUf8_bfOUp7jGkDT_Ga2b4Phn7rZmLZMka9bJayGUVIrA/exec?sensor=35&date=1103
// String urlFinal = "https://script.google.com/macros/s/"+GOOGLE_SCRIPT_ID+"/exec?"+ "sensor=" + String(co2[0]) +"&date=" + String(timestamps[0].unixtime()) ;
//https://docs.google.com/spreadsheets/d/1PVsv0qqtf9gSU1Fq5UKGSFDTeh-USfFxXvHpnTH-bdM/edit#gid=0
String urlFinal = "https://script.google.com/macros/s/"+GOOGLE_SCRIPT_ID+"/exec?"+ "patientnumber=" + String(patientnumber) +"&unixtime=" + String(timestamps[0].unixtime()) + "&o2=" + String(o2[0]) + "&temperature=" + String(temperature[0])+ "&pressure=" + String(pressure[0]) + "&co2=" + String(co2[0],3) + "&volts=" + String(volts[0]) + "&batt_percent=" + String(batt_percent[0]) ;
Serial.print("POST data to spreadsheet:");
Serial.println(urlFinal);
HTTPClient http;
http.begin(urlFinal.c_str());
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
int httpCode = http.GET();
Serial.print("HTTP Status Code: ");
Serial.println(httpCode);
//---------------------------------------------------------------------
//getting response from google sheet
String payload;
if (httpCode > 0) {
payload = http.getString();
Serial.println("Payload: "+payload);
}
//---------------------------------------------------------------------
http.end();
}
else {Serial.println("Wifi not connected!");}
count++;
if(graphy<240){graphy++;}
stamps ++;
if (stamps>RECORDS){Serial.println(dataString);}
}
/************************Detail background***************************/
void detailbackground() {
tft.setRotation(2);
tft.setCursor(0, 0);
tft.setTextColor(ILI9341_WHITE);
tft.setTextWrap(true);
tft.setTextSize(2);
tft.print("");
tft.setTextSize(1);
tft.setCursor(195, 0);
tft.print("Battery");
// tft.drawFastHLine(0, 16, 301, ILI9341_WHITE);
tft.setCursor(100,16);
tft.setTextSize(2);
tft.print("CO2% ");
tft.setCursor(100,86);
tft.print("O2% ");
tft.setCursor(100,156);
tft.print("hPa ");
tft.setCursor(100,226);
tft.print("Cent");
tft.setCursor(103,304);
tft.setTextSize(1);
tft.print("Time");
if (screen == 1) {
tft.setCursor(105,312);
tft.print("Raw");}
else {
tft.setCursor(99,312);
tft.print("Minutes");}
}
/***********************************************Detail screen*****/
void detailscreen(int dgraphy, DateTime dtimestamps[], float dco2[], float do2[], float dtemperature[], float dpressure[]) {
float o2max = o2ambient;
float o2min = o2ambient;
float co2max = co2ambient;
float co2min = co2ambient;
float temperaturemax = 30;
float temperaturemin = 20;
float pressuremax = 1010;
float pressuremin = 980;
char timestring[50] = "\0";
/*Time mins and maxes*/
tft.fillRect(0, 303, 100, 16, ILI9341_BLACK);
tft.setTextSize(2);
tft.setTextColor(ILI9341_WHITE);
tft.setCursor(0, 303);
sprintf(timestring, "%02d",dtimestamps[dgraphy].hour());
sprintf(timestring + strlen(timestring), "%s",":");
sprintf(timestring + strlen(timestring), "%02d",dtimestamps[dgraphy].minute());
if (screen==1)
{
sprintf(timestring + strlen(timestring), "%s",":");
sprintf(timestring + strlen(timestring), "%02d",dtimestamps[dgraphy].second());
}
tft.print(timestring);
tft.fillRect(139, 303, 100, 16, ILI9341_BLACK);
tft.setTextSize(2);
tft.setTextColor(ILI9341_WHITE);
tft.setCursor(139, 303);
sprintf(timestring, "%02d",dtimestamps[0].hour());
sprintf(timestring + strlen(timestring), "%s",":");
sprintf(timestring + strlen(timestring), "%02d",dtimestamps[0].minute());
if (screen==1)
{
sprintf(timestring + strlen(timestring), "%s",":");
sprintf(timestring + strlen(timestring), "%02d",dtimestamps[0].second());
}
else {tft.setCursor(179, 303);}
tft.print(timestring);
/*calculate mins and maxes*/
o2min=do2[0];
o2max=do2[0];
co2min=dco2[0];
co2max=dco2[0];
pressuremin=dpressure[0];
pressuremax=dpressure[0];
temperaturemin=dtemperature[0];
temperaturemax=dtemperature[0];
for (int count = dgraphy; count > 0; count--) {
if (do2[count]>o2max){o2max=do2[count];}
if (do2[count]<o2min){o2min=do2[count];}
if (dco2[count]>co2max){co2max=dco2[count];}
if (dco2[count]<co2min){co2min=dco2[count];}
if (dpressure[count]>pressuremax){pressuremax=dpressure[count];}
if (dpressure[count]<pressuremin){pressuremin=dpressure[count];}
if (dtemperature[count]>temperaturemax){temperaturemax=dtemperature[count];}
if (dtemperature[count]<temperaturemin){temperaturemin=dtemperature[count];}
}
/*CO2 graphing*/
tft.fillRect(169, 16, 70, 16, ILI9341_BLACK);
if((dco2[0]<co2low) || (dco2[0]>co2high)) {tft.setTextColor(NotAmbientColor);}
else {tft.setTextColor(ILI9341_WHITE);}
tft.setTextSize(2);
if(dco2[0]<10){tft.setCursor(179, 16);}
else {tft.setCursor(169, 16);}
tft.print(dco2[0], 3);
tft.fillRect(0, 86, 35, 8, ILI9341_BLACK);
tft.setTextSize(1);
tft.setTextColor(ILI9341_WHITE);
tft.setCursor(0, 86);
tft.print(co2min, 3);
tft.fillRect(0, 24, 35, 8, ILI9341_BLACK);
tft.setCursor(0, 24);
tft.print(co2max, 3);
/*O2 graphing*/
tft.fillRect(169, 86, 70, 16, ILI9341_BLACK);
if((do2[0]<o2low) || (do2[0]>o2high)) {tft.setTextColor(NotAmbientColor);}
else {tft.setTextColor(ILI9341_WHITE);}
tft.setTextSize(2);
tft.setCursor(179, 86);
tft.print(do2[0], 2);
tft.fillRect(0, 156, 35, 8, ILI9341_BLACK);
tft.setTextSize(1);
tft.setTextColor(ILI9341_WHITE);
tft.setCursor(0, 156);
tft.print(o2min, 2);
tft.fillRect(0, 94, 35, 8, ILI9341_BLACK);
tft.setCursor(0, 94);
tft.print(o2max, 2);
/*Pressure graphing*/
tft.fillRect(169, 156, 70, 16, ILI9341_BLACK);
if(dpressure[0]<lowpressure) {tft.setTextColor(NotAmbientColor);}
else {tft.setTextColor(ILI9341_WHITE);}
tft.setTextSize(2);
tft.setCursor(179, 156);
tft.print(dpressure[0], 1);
tft.fillRect(0, 226, 35, 8, ILI9341_BLACK);
tft.setTextSize(1);
tft.setTextColor(ILI9341_WHITE);
tft.setCursor(0, 226);
tft.print(pressuremin, 1);
tft.fillRect(0, 164, 35, 8, ILI9341_BLACK);
tft.setCursor(0, 164);
tft.print(pressuremax, 1);
/*temperature graphing*/
tft.fillRect(169, 226, 70, 16, ILI9341_BLACK);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(2);
tft.setCursor(179, 226);
tft.print(dtemperature[0], 1);
tft.fillRect(0, 296, 35, 8, ILI9341_BLACK);
tft.setTextSize(1);
tft.setTextColor(ILI9341_WHITE);
tft.setCursor(0, 296);
tft.print(temperaturemin, 1);
tft.fillRect(0, 234, 35, 8, ILI9341_BLACK);
tft.setCursor(0, 234);
tft.print(temperaturemax, 1);
/*Battery*/
tft.fillRect(210, 8, 30, 8, ILI9341_BLACK);
tft.setTextSize(1);
tft.setTextColor(ILI9341_WHITE);
tft.setCursor(215, 8);
// if (volts[0]>lowvolts) {tft.print(volts[0], 2);} else {tft.setTextColor(NotAmbientColor); tft.print("LOW");}
if (batt_percent[0]>lowbatt_percent) {
tft.print(batt_percent[0], 0);
tft.print("%");
}
else {tft.setTextColor(NotAmbientColor); tft.print("LOW");}
/*chart*/
for (int count = 0; count < dgraphy; count++) {
// if((co2[0]<co2low) || (co2[0]>co2high)) {tft.setTextColor(NotAmbientColor);}
// else {tft.setTextColor(ILI9341_WHITE);}
tft.drawFastVLine(dgraphy-count, 32, 53, ILI9341_BLACK);
if((dco2[count]<co2low) || (dco2[count]>co2high)) {
tft.drawFastVLine(dgraphy-count, 85, -53*(dco2[count]-co2min)/(co2max-co2min), NotAmbientColor);}
else {
tft.drawFastVLine(dgraphy-count, 85, -53*(dco2[count]-co2min)/(co2max-co2min), ILI9341_CYAN);}
tft.drawFastVLine(dgraphy-count, 102, 53, ILI9341_BLACK);
if((do2[count]<o2low) || (do2[count]>o2high)) { //Used to read o2[count], which looked like a bug
tft.drawFastVLine(dgraphy-count, 155, -53*(do2[count]-o2min)/(o2max-o2min), NotAmbientColor);}
else {
tft.drawFastVLine(dgraphy-count, 155, -53*(do2[count]-o2min)/(o2max-o2min), ILI9341_CYAN);}
tft.drawFastVLine(dgraphy-count, 172, 53, ILI9341_BLACK);
if (dpressure[count]<lowpressure) {
tft.drawFastVLine(dgraphy-count, 225, -53*(dpressure[count]-pressuremin)/(pressuremax-pressuremin), NotAmbientColor);}
else {
tft.drawFastVLine(dgraphy-count, 225, -53*(dpressure[count]-pressuremin)/(pressuremax-pressuremin), ILI9341_CYAN);}
tft.drawFastVLine(dgraphy-count, 242, 53, ILI9341_BLACK);
tft.drawFastVLine(dgraphy-count, 295, -53*(dtemperature[count]-temperaturemin)/(temperaturemax-temperaturemin), ILI9341_CYAN);
}
tft.setTextSize(2);
tft.fillRect(0, 0, 130, 16, ILI9341_BLACK);
tft.setCursor(0, 0);
if(dco2[0]<co2low || dco2[0]>co2high || do2[0]<o2low || do2[0]>o2high) {
tft.setTextColor(NotAmbientColor);
tft.print("NOT AMBIENT");
}
else{
tft.setTextColor(ILI9341_WHITE);
tft.print("AMBIENT");
}
}
/***********************************************MAIN screen******/
void mainscreen() {
// tft.fillScreen(ILI9341_BLACK);
tft.setRotation(2);
tft.setCursor(0, 0);
tft.setTextColor(ILI9341_WHITE);
tft.setTextWrap(true);
tft.setTextSize(3);
tft.print("Battery ");
tft.fillRect(140, 0, 100, 24, ILI9341_BLACK);
// tft.setCursor(295, 8);
// if (volts[0]>lowvolts) {tft.println(volts[0], 2);} else {tft.println("LOW");}
if (batt_percent[0]>lowbatt_percent) {
tft.print(batt_percent[0], 0);
tft.println("%");
}
else {tft.setTextColor(NotAmbientColor); tft.println("LOW");}
tft.setTextSize(3);
tft.println("");
tft.setTextSize(6);
tft.fillRect(0, 48, 240, 48, ILI9341_BLACK);
if((co2[0]<co2low) || (co2[0]>co2high)) {
tft.setTextColor(NotAmbientColor);}
else {
tft.setTextColor(ILI9341_WHITE);}
tft.println(co2[0], 3);
tft.setTextSize(3);
tft.println("");
tft.setTextSize(6);
tft.fillRect(0, 120, 240, 48, ILI9341_BLACK);
if((o2[0]<o2low) || (o2[0]>o2high)) {
tft.setTextColor(NotAmbientColor);}
else {
tft.setTextColor(ILI9341_WHITE);}
tft.println(o2[0], 2);
tft.setTextSize(3);
tft.println("");
tft.setTextSize(6);
tft.fillRect(0, 192, 240, 48, ILI9341_BLACK);
if(pressure[0]<lowpressure) {
tft.setTextColor(NotAmbientColor);}
else {
tft.setTextColor(ILI9341_WHITE);}
tft.println(pressure[0], 1);
tft.setTextSize(3);
tft.println("");
tft.setTextSize(6);
tft.fillRect(0, 264, 240, 48, ILI9341_BLACK);
tft.setTextColor(ILI9341_WHITE);
tft.println(temperature[0], 1);
tft.setTextSize(1);
tft.setCursor(0,312);
tft.print("Patient Number ");
tft.print(patientnumber);
tft.print(" ");
if (WiFi.status() != WL_CONNECTED){tft.setTextColor(ILI9341_RED);}
else {tft.setTextColor(ILI9341_GREEN);}
tft.print("WiFi");
tft.print(" ");
if (sdflag != 0){tft.setTextColor(ILI9341_RED);}
else {tft.setTextColor(ILI9341_GREEN);}
tft.print("SD");
}
/***********************************************MAIN screen******/
void mainscreenbackground() {
tft.fillScreen(ILI9341_BLACK);
tft.setRotation(2);
tft.setCursor(0, 0);
tft.setTextColor(ILI9341_WHITE);
tft.setTextWrap(true);
tft.setTextSize(3);
tft.println("Battery");
tft.setTextSize(3);
tft.println(" CO2-%");
tft.setTextSize(6);
tft.println("");
tft.setTextSize(3);
tft.println(" O2-%");
tft.setTextSize(6);
tft.println("");
tft.setTextSize(3);
tft.println(" Pressure-hPa");
tft.setTextSize(6);
tft.println("");
tft.setTextSize(3);
tft.println(" Temp-C");
tft.setTextSize(6);
tft.println("");
}