#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <Wire.h> // Required for I2C communication
// Define TFT display pins
#define TFT_CS 15
#define TFT_DC 2
#define TFT_SCK 18
#define TFT_MOSI 23
// Create TFT object
//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCK);
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// Function prototype
void setup_tft();
void setup_Pins();
void drawLayout();
void drawHeader();
void drawActionArea();
void drawAlarmSection();
void drawBox(int index, uint16_t color);
void drawLabel(int index);
void updateBox(int index);
void updateActionArea();
void updateAlarmMessage(const char* message);
void displayIPAddress();
void updateIPAddressIfChanged();
// Define dimensions for different sections
#define HEADER_HEIGHT 18
#define BODY_HEIGHT 170
#define BODY_WIDTH 260
#define ACTION_AREA_HEIGHT (BODY_HEIGHT)
#define ACTION_AREA_WIDTH (tft.width() - BODY_WIDTH)
#define BOX_SIZE 20
#define BOX_HORIZONTAL_SPACING 12 // Horizontal spacing between boxes
#define BOX_VERTICAL_SPACING 18 // Vertical spacing between boxes
#define ACTION_BOX_SIZE 20
#define ACTION_BOX_SPACING 15
char alarm_msg[100]; // Fixed-size character array
// Define the number of buttons and their corresponding pins
const int numButtons = 32; // Adjust this value for the number of buttons
int buttonPins[] = {22,12,14,27,26,25,33,32}; // Array of button pins
const char* pinNames[] = {"22", "12", "14", "27", "26", "25", "33", "32"}; // buttonpins names
//Get the number of pins to monitor
const int buttonsPinsSize = sizeof(buttonPins) / sizeof(buttonPins[0]);
const int pinNamesSize = sizeof(pinNames) / sizeof(pinNames[0]);
// Define the number of relay and their corresponding pins
const int numRelays = 4; // Adjust this value for the number of buttons
int relayPins[] = {5,16,17}; // Array of button pins //,21
const char* relayNames[] = {"5", "16", "17"}; // relaypin names //, "21"
//Get the number of pins to monitor
const int relayPinsSize = sizeof(relayPins) / sizeof(relayPins[0]);
const int relayNamesSize = sizeof(relayNames) / sizeof(relayNames[0]);
bool ActionRelay_state = 0;
String currentIP;
void setup() {
// Initialize serial communication
Serial.begin(115200);
// Initialize the TFT display
setup_tft();
// Set up pins and draw initial layout
setupPins();
drawLayout();
displayIPAddress();
}
void loop() {
for (int i = 0; i < buttonsPinsSize; i++) {
updateBox(i);
sprintf(alarm_msg, "Box: Value is %d next line \n box: value is ", i);
updateAlarmMessage(alarm_msg);
}
for (int i = 0; i < relayPinsSize; i++) {
int currentState = digitalRead(relayPins[i]);
updateActionArea(i, currentState);
}
updateIPAddressIfChanged();
delay(100); // Small delay to debounce buttons and reduce flickering
}
// Functions definition
// Function initialize the TFT display
void setup_tft(){
tft.begin();
tft.setRotation(1); // Rotate display as needed
tft.fillScreen(ILI9341_BLACK); // Clear the screen
}
// Function to set up pins
void setupPins() {
for (int i = 0; i < numButtons; i++) {
pinMode(buttonPins[i], INPUT_PULLDOWN);
}
for (int i = 0; i < numRelays; i++) {
pinMode(relayPins[i], INPUT_PULLDOWN);
}
}
// Function to draw the dashboard layout
void drawLayout() {
// Draw the header area
drawHeader();
// Draw the action area on the right
drawActionArea();
// Draw the alarm section
drawAlarmSection();
// Draw the body section for buttons
for (int i = 0; i < numButtons; i++) {
drawBox(i, ILI9341_DARKGREY); // Draw each box with initial color blue
drawLabel(i); // Draw label under each box
}
// Draw the body section for buttons actual in use
for (int i = 0; i < buttonsPinsSize; i++) {
drawBox(i, ILI9341_BLUE); // Draw each box with initial color blue
drawLabel(i); // Draw label under each box
}
// Update status
for (int i = 0; i < buttonsPinsSize; i++) {
updateBox(i);
sprintf(alarm_msg, "Box: Value is %d", i);
updateAlarmMessage(alarm_msg);
}
}
// Function to draw the header
void drawHeader() {
tft.fillRect(0, 0, tft.width(), HEADER_HEIGHT, ILI9341_NAVY);
tft.drawRect(0, 0, tft.width(), HEADER_HEIGHT, ILI9341_WHITE); // Border for the header
tft.setCursor(2, 6);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(1);
tft.print(" Dashboard");
tft.drawRect(0, 0, tft.width(), HEADER_HEIGHT + BODY_HEIGHT, ILI9341_WHITE);
}
// Function to draw the action area with status boxes
void drawActionArea() {
tft.drawRect(BODY_WIDTH, HEADER_HEIGHT - 1, ACTION_AREA_WIDTH, ACTION_AREA_HEIGHT, ILI9341_WHITE); // Border for action area
// Draw action area header
tft.fillRect(BODY_WIDTH, HEADER_HEIGHT-1, ACTION_AREA_WIDTH, 16, ILI9341_NAVY);
tft.drawRect(BODY_WIDTH, HEADER_HEIGHT-1, ACTION_AREA_WIDTH, 16, ILI9341_WHITE);
tft.setCursor(BODY_WIDTH + 6, HEADER_HEIGHT + 4);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(1);
tft.print(" Action");
int baseX = BODY_WIDTH + 10;
int baseY = HEADER_HEIGHT + 30;
// Draw the action relay boxes
for (int i = 0; i < numRelays; i++) {
int boxY = baseY + i * (ACTION_BOX_SIZE + ACTION_BOX_SPACING);
tft.fillRoundRect(baseX, boxY, ACTION_AREA_WIDTH - 18, ACTION_BOX_SIZE, 4, ILI9341_DARKGREY);
tft.drawRoundRect(baseX, boxY, ACTION_AREA_WIDTH - 18, ACTION_BOX_SIZE, 4, ILI9341_WHITE); // Border for each status box
}
for (int i = 0; i < relayPinsSize; i++) {
int boxY = baseY + i * (ACTION_BOX_SIZE + ACTION_BOX_SPACING);
tft.fillRoundRect(baseX, boxY, ACTION_AREA_WIDTH - 18, ACTION_BOX_SIZE, 4, ILI9341_BLUE);
tft.drawRoundRect(baseX, boxY, ACTION_AREA_WIDTH - 18, ACTION_BOX_SIZE, 4, ILI9341_WHITE); // Border for each status box
tft.setCursor(baseX + 4, boxY + 6);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(1);
tft.print("R");
tft.print(i + 1);
tft.print(":");
tft.print(ActionRelay_state? "ON":"OFF");
}
}
// Function to draw the alarm section layout with a vertical header
void drawAlarmSection() {
// Calculate start position for the alarm section
int startY = HEADER_HEIGHT + (ACTION_AREA_HEIGHT - 2);
// Draw the alarm section background and border
tft.fillRect(0, startY, tft.width(), tft.height() - startY, ILI9341_BLACK);
tft.drawRect(0, startY, tft.width(), tft.height() - startY, ILI9341_WHITE); // Border for the alarm section
// Draw the alarm section header and border
tft.fillRect(0, startY, 15, tft.height() - startY, ILI9341_NAVY);
tft.drawRect(0, startY, 15, tft.height() - startY, ILI9341_WHITE); // Border for the alarm section
// Set text properties for vertical "ALARM" header
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(1); // Adjust text size as needed
// Draw each letter of "ALARM" vertically
int cursorX = 4; // X position for the vertical text
int cursorY = startY + 3; // Starting Y position
// Print each character on a new line
tft.setCursor(cursorX, cursorY);
tft.print('A');
cursorY += 10; // Move down for the next character
tft.setCursor(cursorX, cursorY);
tft.print('L');
cursorY += 10;
tft.setCursor(cursorX, cursorY);
tft.print('A');
cursorY += 10;
tft.setCursor(cursorX, cursorY);
tft.print('R');
cursorY += 10;
tft.setCursor(cursorX, cursorY);
tft.print('M');
}
// Function to draw a single box
void drawBox(int index, uint16_t color) {
// Calculate the maximum number of boxes that can fit in one row
int maxBoxesPerRow = (BODY_WIDTH) / (BOX_SIZE + BOX_HORIZONTAL_SPACING);
// Calculate the x and y positions based on the index
int row = index / maxBoxesPerRow; // Determine the current row
int col = index % maxBoxesPerRow; // Determine the position in the current row
// Calculate the x and y position for the box
int boxX = (BOX_HORIZONTAL_SPACING / 2) + (col * (BOX_SIZE + BOX_HORIZONTAL_SPACING));
int boxY = HEADER_HEIGHT + 6 + (row * (BOX_SIZE + BOX_VERTICAL_SPACING));
// Draw the box at the calculated position
tft.fillRoundRect(boxX, boxY, BOX_SIZE, BOX_SIZE, 4, color);
tft.drawRoundRect(boxX, boxY, BOX_SIZE, BOX_SIZE, 4, ILI9341_WHITE); // Border for each box
}
// Function to draw label for a box
void drawLabel(int index) {
int maxBoxesPerRow = (BODY_WIDTH) / (BOX_SIZE + BOX_HORIZONTAL_SPACING);
int row = index / maxBoxesPerRow; // Determine the current row
int col = index % maxBoxesPerRow; // Determine the position in the current row
// Calculate the x and y position for the label
int labelX = (BOX_HORIZONTAL_SPACING / 2) + (col * (BOX_SIZE + BOX_HORIZONTAL_SPACING)+2); // Adjusted X position
int labelY = HEADER_HEIGHT + 6 + (row * (BOX_SIZE + BOX_VERTICAL_SPACING)) + BOX_SIZE + 4; // Adjust Y position to be just below the box
// Draw the label at the calculated position
tft.setCursor(labelX, labelY);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(1);
tft.print("D");
tft.print(index + 1);
}
// Function to update a box based on button state
void updateBox(int index) {
int buttonState = digitalRead(buttonPins[index]);
uint16_t color = (buttonState == HIGH) ? ILI9341_GREEN : ILI9341_BLUE;
drawBox(index, color);
}
// Function to update actionarea based on relay state
void updateActionArea(int index, int state) {
// Define colors for ON and OFF states
uint16_t colorOn = ILI9341_GREEN;
uint16_t colorOff = ILI9341_RED;
// Determine the color based on the relay state
uint16_t color = (state == HIGH) ? colorOn : colorOff;
// Define box positions and sizes
int boxWidth = 100; // Width of the box
int boxHeight = 30; // Height of the box
int boxPadding = 5; // Padding between boxes
int startX = tft.width() - 200; // X position of the action area
int startY = HEADER_HEIGHT;
// Calculate the position of the box based on index
int posX = startX;
int posY = startY + (index * (boxHeight + boxPadding));
// Draw the box with the current color
tft.fillRect(posX, posY, boxWidth, boxHeight, color);
tft.drawRect(posX, posY, boxWidth, boxHeight, ILI9341_WHITE);
// Draw the label inside the box
tft.setCursor(posX + 5, posY + 5); // Adjust position as needed
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(1);
tft.print(relayNames[index]);
}
// Function to update the custom message within the alarm section
void updateAlarmMessage(const char* message) {
int16_t startX = 16; // X position where the message starts
int16_t startY = HEADER_HEIGHT + (ACTION_AREA_HEIGHT - 2) + 2; // Y position where the message starts
int16_t sectionWidth = tft.width() - startX - 2; // Width of the text area
int textSize = 1; // Text size for this function
int16_t lineHeight = 10; // Height of each text line (adjust if needed)
// Clear the area where the message will be displayed
tft.fillRect(startX, startY, sectionWidth, tft.height() - startY, ILI9341_BLACK);
// Set text properties
tft.setTextColor(ILI9341_GREEN);
tft.setTextSize(textSize);
int16_t cursorX = startX;
int16_t cursorY = startY;
String msg = String(message); // Convert C-string to String for easier handling
int lastIndex = 0; // Last index processed in the message
// Loop through the message to wrap text and handle newlines
while (lastIndex < msg.length()) {
int nextLineIndex = msg.indexOf('\n', lastIndex);
String line = (nextLineIndex == -1) ? msg.substring(lastIndex) : msg.substring(lastIndex, nextLineIndex);
// Get text bounds
uint16_t textWidth, textHeight;
int16_t x1, y1;
tft.getTextBounds(line, cursorX, cursorY, &x1, &y1, &textWidth, &textHeight);
// Check if the line fits within the width
if (cursorX + textWidth > sectionWidth + startX) {
cursorX = startX; // Reset X position
cursorY += lineHeight; // Move down for the next line
}
// Print the current line
tft.setCursor(cursorX, cursorY);
tft.print(line);
// Update positions
cursorX += textWidth; // Move cursor to the end of the printed line
// Move to the next line if there was a newline character
lastIndex = (nextLineIndex == -1) ? msg.length() : nextLineIndex + 1;
if (nextLineIndex != -1) {
cursorX = startX; // Reset X position
cursorY += lineHeight; // Move down for the next line
}
}
}
// Function to display the IP address on the TFT display
void displayIPAddress() {
// Fetch the current IP address
//IPAddress ip = Ethernet.localIP();
String ip = "192.168.100.101";
// Set text color and size
tft.setTextColor(ILI9341_WHITE, ILI9341_NAVY); // White text on a black background
tft.setTextSize(1);
// Print the IP address on the TFT display
tft.setCursor(200, 6); // Set cursor position (adjust as needed)
tft.print("IP: ");
tft.println(ip);
// Update the global IP address variable
currentIP = ip;
}
// Function to monitor and update the IP address if it changes
void updateIPAddressIfChanged() {
//IPAddress newIP = Ethernet.localIP();
String newIP = "192.168.1.301";
// Check if the IP address has changed
if (newIP != currentIP) {
// Clear the old IP address from the screen
tft.fillRect(200, 5, 114, 10, ILI9341_WHITE); // Clear the area where the IP is displayed
// Update the IP address on the display
displayIPAddress();
}
}