Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions IoT_Wearable/Codebase/Complete_Code/dev_display_driver/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// This is used for:
// - Arduino Nano 33 IoT board, paired with
// - WaveShare ST7789v2 display module

#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7789.h> // Hardware-specific library for ST7789, used for initializing display object
#include <SPI.h>
#include <WiFiNINA.h>
#include <WiFiUdp.h>
#include <RTCZero.h>

//Include user defined header files
#include <template.h>
#include <wifi_time.h>

//Setting up the pins
#define TFT_CS 10
#define TFT_RST 8
#define TFT_DC 9

// We are using the HARDWARE SPI pins for MOSI and SCLK, which are unique
// to each board and not reassignable. For Arduino Nano 33 IoT: MOSI = pin 11 and
// SCLK = pin 13. This is done to improve the performance of the display.

// Create a display object of the Adafruit_ST7789 class
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);

//Declare rtc object for real time clock
RTCZero rtc;


void drawTemplate() {
tft.fillScreen(ST77XX_BLACK); //Clear screen before redrawing

uint8_t padding = 10; // Padding for layout

// Top Section: Battery level with battery icon
drawBatteryIcon(tft, padding + 10, padding + 10, ST77XX_WHITE); // Draw battery icon with 85% charge

// First Section: Heart Rate and SpO2
drawHeartIcon(tft, padding + 10, padding + 170, ST77XX_RED); // Heart icon
drawBubbleIcon(tft, padding + 10, padding + 240, ST77XX_CYAN); // Bubble icon with SpO2 percentage

drawCircularStepsGauge(tft, 170, 220, 2000, 10000, ST77XX_GREEN);

// Fourth Section: Body Temperature
drawThermometerIcon(tft, padding + 10, padding + 200); // Thermometer icon

// Use the new RTC-aware version of drawTime
drawTime(tft, rtc, 20, 85, ST77XX_WHITE);
drawDate(tft, rtc, 120, 25, ST77XX_WHITE);
}

void setup() {
// Initialize Serial Monitor
Serial.begin(9600);
Serial.println(F("Initializing ST7789 Display..."));

// Initialize WiFi
WiFi_Setup(WiFi, rtc);

// Initialize display (240x280 resolution)
tft.init(240, 280);
tft.setRotation(2); // Portrait orientation
tft.fillScreen(ST77XX_BLACK);

// Set default text size and color
tft.setTextSize(2);
tft.setTextColor(ST77XX_WHITE);

// Draw the template
drawTemplate();
}

void loop() {
// Continuously update the time every second
delay(3000); // Wait for 3 seconds
drawTemplate(); // Redraw the template to update the time
}
169 changes: 169 additions & 0 deletions IoT_Wearable/Codebase/Complete_Code/dev_display_driver/template.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
#ifndef template_h
#define template_h

#include <Adafruit_GFX.h> // Core graphics library for displays
#include <Adafruit_ST7789.h> // Specific driver for the ST7789 display
#include <SPI.h> // SPI communication used for the display

/**
* Get the name of the weekday for a given date using Zeller's Congruence.
*
* @param day Day of the month
* @param month Month (1 = January, 12 = December)
* @param year Full year (e.g., 2024)
* @return Abbreviated weekday name (e.g., "Mon", "Tue", ...)
*/
const char* weekdayName(int day, int month, int year) {
if (month < 3) {
month += 12;
year -= 1;
}

int k = year % 100;
int j = year / 100;
int h = (day + (13 * (month + 1)) / 5 + k + k/4 + j/4 + 5*j) % 7;

const char* days[] = {"Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri"};
return days[h];
}

/**
* Draws a battery icon on the display, representing battery percentage visually.
*/
void drawBatteryIcon(Adafruit_ST7789 tft, int x, int y, uint16_t color) {
tft.drawRect(x, y, 50, 25, color); // Battery body outline
tft.fillRect(x + 52, y + 7, 5, 12, color); // Battery terminal
tft.fillRect(x + 2, y + 2, 46, 21, ST77XX_BLACK); // Battery "empty" interior

// Display the battery percentage as text
tft.setCursor(x + 8, y + 5);
tft.setTextColor(color);
tft.setTextSize(2);
tft.print("80%");
}

/**
* Draws a heart icon and displays a heart rate value.
*/
void drawHeartIcon(Adafruit_ST7789 tft, int x, int y, uint16_t color) {
tft.fillCircle(x + 4, y + 4, 4, color); // Left part of the heart
tft.fillCircle(x + 12, y + 4, 4, color); // Right part of the heart
tft.fillTriangle(x, y + 4, x + 8, y + 16, x + 16, y + 4, color); // Bottom point

// Display heart rate
tft.setCursor(x + 25, y);
tft.setTextColor(ST77XX_WHITE);
tft.setTextSize(2);
tft.print("76");
}

/**
* Draws a bubble (oxygen) icon and displays an SpO2 percentage value.
*/
void drawBubbleIcon(Adafruit_ST7789 tft, int x, int y, uint16_t color) {
tft.drawCircle(x + 8, y + 8, 8, color); // Outer bubble outline
tft.fillCircle(x + 6, y + 6, 2, color); // Highlight dot inside

// Display SpO2 percentage
tft.setCursor(x + 25, y);
tft.setTextColor(ST77XX_WHITE);
tft.setTextSize(2);
tft.print("98%");
}

/**
* Draws a thermometer icon and displays a body temperature reading.
*/
void drawThermometerIcon(Adafruit_ST7789 tft, int x, int y) {
tft.fillRect(x + 4, y + 2, 4, 12, ST77XX_WHITE); // Thermometer stem
tft.fillCircle(x + 6, y + 16, 3, ST77XX_WHITE); // Thermometer bulb (outer)
tft.fillRect(x + 5, y + 7, 2, 12, ST77XX_RED); // Mercury (stem)
tft.fillCircle(x + 6, y + 16, 2, ST77XX_RED); // Mercury (bulb)

// Display body temperature
tft.setCursor(x + 25, y + 3);
tft.setTextColor(ST77XX_WHITE);
tft.setTextSize(2);
tft.print("36.4C");
}

/**
* Displays the current time in HH:MM format using RTCZero.
*/
void drawTime(Adafruit_ST7789 tft, RTCZero& rtc, int x, int y, uint16_t color) {
int hours = rtc.getHours();
int minutes = rtc.getMinutes();

tft.setCursor(x, y);
tft.setTextColor(color);
tft.setTextSize(7);
if (hours < 10) tft.print("0");
tft.print(hours);
tft.print(":");
if (minutes < 10) tft.print("0");
tft.print(minutes);
}

/**
* Displays the current date in format: Weekday DD/MM using RTCZero.
*/
void drawDate(Adafruit_ST7789 tft, RTCZero& rtc, int x, int y, uint16_t color) {
int day = rtc.getDay();
int month = rtc.getMonth();
int year = rtc.getYear() + 2000;

const char* weekday = weekdayName(day, month, year);

tft.setCursor(x, y);
tft.setTextColor(color);
tft.setTextSize(2);
tft.print(weekday);
tft.print(" ");

if (day < 10) tft.print("0");
tft.print(day);
tft.print("/");

if (month < 10) tft.print("0");
tft.print(month);
}

/**
* Draws a circular step counter gauge showing progress toward a step goal.
*/
void drawCircularStepsGauge(Adafruit_ST7789 tft, int x, int y, int steps, int maxSteps, uint16_t color) {
// Draw outer circle for gauge
tft.fillCircle(x, y, 50, ST77XX_BLACK); // Background
tft.drawCircle(x, y, 50, ST77XX_WHITE); // Border

// Convert step count to angle (0° to 360°)
int angle = map(steps, 0, maxSteps, 0, 360);

// Draw each pixel along the arc
for (int i = 0; i < angle; i++) {
int x1 = x + 50 * cos(radians(i));
int y1 = y - 50 * sin(radians(i));
tft.drawPixel(x1, y1, color);
}

// Label: "Steps" above gauge
tft.setCursor(x - 15, y - 25);
tft.setTextColor(ST77XX_WHITE);
tft.setTextSize(1);
tft.print("Steps");

// Display current step count in center
tft.setCursor(x - 22, y - 5);
tft.setTextColor(ST77XX_WHITE);
tft.setTextSize(2);
tft.print(steps);

// Display goal step count below
tft.setCursor(x - 15, y + 25);
tft.setTextColor(ST77XX_WHITE);
tft.setTextSize(1);
tft.print("/");
tft.print(maxSteps);
}

#endif

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way the WIFI credentials are setup here may lead to possible data breaches or unauthorised access to networks. While it is a placeholder and needs to be replaced by a user, it could possibly lead to someone having their information exposed once they add their credentials in.

Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#ifndef wifi_time_h
#define wifi_time_h

#include <WiFiNINA.h> // WiFi library for Arduino boards using NINA module
#include <WiFiUdp.h> // Required for time retrieval using NTP
#include <RTCZero.h> // Real-time clock library

// Debug toggle: Set to false to disable Serial prints
bool WIFI_DEBUG = true;

// WiFi credentials
#define SECRET_SSID "REPLACE_WITH_YOUR_SSID"
#define SECRET_PASS "REPLACE_WITH_YOUR_PASSWORD"

// WiFi connection status tracking variable
int status = WL_IDLE_STATUS;

/**
* Function to connect to WiFi and synchronize RTC with NTP time.
*
* @param wifi Reference to the WiFi module instance (usually `WiFi`)
* @param rtc Reference to RTCZero instance used for tracking real time
*
* @return true if setup was successful and time was synced, false otherwise
*/
bool WiFi_Setup(WiFiClass& wifi, RTCZero& rtc) {
// Check if WiFi module is present and working
if (wifi.status() == WL_NO_SHIELD) {
if (WIFI_DEBUG) Serial.println("WiFi adapter not ready");
return false; // Exit early if WiFi hardware is not detected
}

// Attempt to connect to the WiFi network
while (status != WL_CONNECTED) {
if (WIFI_DEBUG) {
Serial.print("Connecting to SSID: ");
Serial.println(SECRET_SSID);
}
status = wifi.begin(SECRET_SSID, SECRET_PASS); // Start connection attempt
delay(3000); // Wait 3 seconds before retrying
}

if (WIFI_DEBUG) Serial.println("WiFi connected!");


// Clock logic to be fixed, currently not accurate

// Initialize the real-time clock
rtc.begin();

// Try to get the current time from an NTP server
unsigned long epoch; // Stores the retrieved epoch time
int tries = 0, maxTries = 6; // Retry up to 6 times

do {
epoch = wifi.getTime(); // Request time from NTP server
tries++;
delay(1000); // Wait 1 second between tries
} while ((epoch == 0) && (tries < maxTries));

// If time could not be retrieved after maxTries, return false
if (tries == maxTries) {
if (WIFI_DEBUG) Serial.println("NTP unreachable!!");
return false;
}

Serial.print("Epoch received: ");
Serial.println(epoch);

// Set RTC time using the retrieved epoch
rtc.setEpoch(epoch);
if (WIFI_DEBUG) Serial.println("Time synced.");

return true;
}

#endif
Loading