#ifndef DISPLAY_H #define DISPLAY_H #include #include #include #include "Config.h" // ==================== فونت‌ها ==================== #include #include #include // ==================== تنظیمات LCD ==================== #define TFT_CS PB0 #define TFT_DC PA4 #define SCREEN_WIDTH 240 #define SCREEN_HEIGHT 240 #define LCD_CENTER_X 120 #define LCD_CENTER_Y 120 // ==================== رنگ‌های سفارشی ==================== #define COLOR_BG_DARK 0x0000 // مشکی #define COLOR_TEMP 0xF800 // قرمز برای دما #define COLOR_HUM 0x001F // آبی برای رطوبت #define COLOR_LIGHT 0xFFE0 // زرد برای نور #define COLOR_GAS 0xFD20 // نارنجی برای گاز #define COLOR_BATTERY 0x07E0 // سبز برای باتری #define COLOR_POWER 0x07FF // آبی فیروزه‌ای برای برق #define COLOR_TEXT 0xFFFF // سفید برای متن #define COLOR_TEXT_DIM 0x7BEF // خاکستری برای متن کمرنگ #define COLOR_HEADER 0x8410 // خاکستری تیره برای هدر // ==================== متغیرهای خارجی ==================== extern Arduino_GC9A01* tft; extern DeviceConfig config; extern SensorData currentData; extern bool sht31Connected; extern bool lightSensorConnected; extern bool coSensorConnected; extern bool calibrationComplete; extern int signalStrength; extern String lastMessage; extern unsigned long lastDisplayChange; // پیش‌اعلام توابع void displayAllParameters(); void updateDisplay(); void initDisplay(); // تعریف توابع // تابع نمایش مقدار با عنوان inline void drawValueWithLabel(String label, String value, int x, int y, uint16_t valueColor) { if (!tft) return; // نمایش عنوان tft->setFont(&FreeSansBold9pt7b); tft->setTextColor(COLOR_TEXT_DIM, COLOR_BG_DARK); tft->setCursor(x, y); tft->print(label); // نمایش مقدار int16_t x1, y1; uint16_t w, h; tft->getTextBounds(label + ":", 0, 0, &x1, &y1, &w, &h); tft->setTextColor(valueColor, COLOR_BG_DARK); tft->setCursor(x + w + 5, y); tft->print(value); } // تابع نمایش هدر inline void drawHeader() { if (!tft) return; // پس زمینه هدر tft->fillRect(0, 0, SCREEN_WIDTH, 40, COLOR_HEADER); // نمایش عنوان دستگاه tft->setFont(&FreeSansBold12pt7b); tft->setTextColor(COLOR_TEXT, COLOR_HEADER); String title = "Station " + String(config.deviceId); int16_t x1, y1; uint16_t w, h; tft->getTextBounds(title, 0, 0, &x1, &y1, &w, &h); tft->setCursor((SCREEN_WIDTH - w) / 2, 30); tft->print(title); } // تابع نمایش دمای بزرگ در مرکز inline void drawLargeTemperature() { if (!tft) return; tft->setFont(&FreeSansBold18pt7b); tft->setTextColor(COLOR_TEMP, COLOR_BG_DARK); String tempText = String(currentData.temperature, 1) + "°C"; int16_t x1, y1; uint16_t w, h; tft->getTextBounds(tempText, 0, 0, &x1, &y1, &w, &h); tft->setCursor((SCREEN_WIDTH - w) / 2, 90); tft->print(tempText); // زیرنویس tft->setFont(&FreeSansBold9pt7b); tft->setTextColor(COLOR_TEXT_DIM, COLOR_BG_DARK); tft->setCursor((SCREEN_WIDTH - 60) / 2, 115); tft->print("Temperature"); } // تابع نمایش اطلاعات در دو ستون inline void drawTwoColumnData() { if (!tft) return; int startY = 130; int rowHeight = 25; // ستون سمت چپ drawValueWithLabel("Humidity:", String(currentData.humidity, 0) + "%", 20, startY, COLOR_HUM); drawValueWithLabel("Light:", String((int)currentData.lightLux) + " lux", 20, startY + rowHeight, COLOR_LIGHT); drawValueWithLabel("Battery:", String(currentData.batteryPercent) + "%", 20, startY + rowHeight * 2, COLOR_BATTERY); // ستون سمت راست drawValueWithLabel("CO:", String((int)currentData.coPPM) + " ppm", 140, startY, COLOR_GAS); drawValueWithLabel("Voltage:", String(currentData.batteryVoltage, 1) + "V", 140, startY + rowHeight, COLOR_POWER); // وضعیت برق tft->setFont(&FreeSansBold9pt7b); if (currentData.power == 1) { tft->setTextColor(COLOR_POWER, COLOR_BG_DARK); tft->setCursor(140, startY + rowHeight * 2); tft->print("Power: ON"); } } // تابع نمایش وضعیت سنسورها inline void drawSensorStatus() { if (!tft) return; int y = 210; tft->setFont(&FreeSansBold9pt7b); // نمایش وضعیت اتصال سنسورها String status = ""; if (!sht31Connected) status += "TEMP "; if (!lightSensorConnected) status += "LIGHT "; if (!coSensorConnected) status += "GAS "; if (status.length() > 0) { tft->setTextColor(COLOR_TEMP, COLOR_BG_DARK); tft->setCursor(10, y); tft->print("Err: " + status); } else { tft->setTextColor(COLOR_BATTERY, COLOR_BG_DARK); tft->setCursor(10, y); tft->print("All Sensors OK"); } // نمایش قدرت سیگنال tft->setTextColor(COLOR_TEXT_DIM, COLOR_BG_DARK); String signalText = "Sig: " + String(signalStrength); int16_t x1, y1; uint16_t w, h; tft->getTextBounds(signalText, 0, 0, &x1, &y1, &w, &h); tft->setCursor(SCREEN_WIDTH - w - 10, y); tft->print(signalText); } // تابع نمایش فاصله آپلود inline void drawUploadInterval() { if (!tft) return; tft->setFont(&FreeSansBold9pt7b); tft->setTextColor(COLOR_TEXT_DIM, COLOR_BG_DARK); String intervalText = "Upload: " + String(config.uploadInterval) + "min"; int16_t x1, y1; uint16_t w, h; tft->getTextBounds(intervalText, 0, 0, &x1, &y1, &w, &h); tft->setCursor((SCREEN_WIDTH - w) / 2, 230); tft->print(intervalText); } inline void displaySimpleMode() { if (!tft) { Serial1.print("Not TFT!!"); return; } // پاک کردن صفحه tft->fillScreen(COLOR_BG_DARK); // ========== نمایش دما بزرگ در مرکز ========== String tempText = String(currentData.temperature, 1) + "°C"; tft->setFont(&FreeSansBold18pt7b); tft->setTextColor(COLOR_TEMP, COLOR_BG_DARK); int16_t x1, y1; uint16_t w, h; tft->getTextBounds(tempText, 0, 0, &x1, &y1, &w, &h); tft->setCursor(LCD_CENTER_X - w/2, LCD_CENTER_Y - 30); tft->print(tempText); // ========== نمایش رطوبت زیر دما ========== tft->setFont(&FreeSansBold12pt7b); String humText = "H:" + String(currentData.humidity, 0) + "%"; tft->getTextBounds(humText, 0, 0, &x1, &y1, &w, &h); tft->setTextColor(COLOR_HUM, COLOR_BG_DARK); tft->setCursor(LCD_CENTER_X - w/2, LCD_CENTER_Y + 20); tft->print(humText); // ========== نمایش باتری و نور در یک خط ========== tft->setFont(&FreeSansBold9pt7b); // باتری String batText = "B:" + String(currentData.batteryPercent) + "%"; if (currentData.power == 1) { batText = "PWR:ON"; } tft->getTextBounds(batText, 0, 0, &x1, &y1, &w, &h); tft->setTextColor(currentData.power == 1 ? COLOR_POWER : COLOR_BATTERY, COLOR_BG_DARK); tft->setCursor(30, 180); // سمت چپ tft->print(batText); // نور String lightText = "L:" + String((int)currentData.lightLux); if (currentData.lightLux > 9999) { lightText = "L:" + String(currentData.lightLux / 1000, 0) + "K"; } tft->getTextBounds(lightText, 0, 0, &x1, &y1, &w, &h); tft->setTextColor(COLOR_LIGHT, COLOR_BG_DARK); tft->setCursor(240 - w - 30, 180); // سمت راست tft->print(lightText); // ========== نمایش CO در پایین مرکز ========== bool gasWarning = currentData.coPPM > 50; String gasText = "CO:" + String((int)currentData.coPPM) + "ppm"; tft->getTextBounds(gasText, 0, 0, &x1, &y1, &w, &h); tft->setTextColor(gasWarning ? COLOR_TEMP : COLOR_GAS, COLOR_BG_DARK); tft->setCursor(LCD_CENTER_X - w/2, 210); tft->print(gasText); // ========== نمایش ولتاژ و شناسه در بالا ========== tft->setFont(&FreeSansBold9pt7b); tft->setTextColor(COLOR_TEXT_DIM, COLOR_BG_DARK); // ولتاژ در سمت چپ بالا String voltageText = String(currentData.batteryVoltage, 1) + "V"; tft->setCursor(10, 20); tft->print(voltageText); // شناسه دستگاه در سمت راست بالا String idText = "#" + String(config.deviceId); tft->getTextBounds(idText, 0, 0, &x1, &y1, &w, &h); tft->setCursor(240 - w - 10, 20); tft->print(idText); // نمایش وضعیت سنسورها در پایین int errorCount = 0; if (!sht31Connected) errorCount++; if (!lightSensorConnected) errorCount++; if (!coSensorConnected) errorCount++; if (errorCount > 0) { tft->setTextColor(COLOR_TEMP, COLOR_BG_DARK); String statusText = String(errorCount) + " ERR"; tft->getTextBounds(statusText, 0, 0, &x1, &y1, &w, &h); tft->setCursor(LCD_CENTER_X - w/2, 230); tft->print(statusText); } } // ==================== طراحی اصلی ==================== inline void GdisplayAllParameters() { if (!tft) { Serial1.print("Not TFT!!"); return; } // پاک کردن صفحه tft->fillScreen(COLOR_BG_DARK); // ========== نمایش دما بزرگ در مرکز ========== String tempText = String(currentData.temperature, 1) + "°C"; tft->setFont(&FreeSansBold18pt7b); tft->setTextColor(COLOR_TEMP, COLOR_BG_DARK); int16_t x1, y1; uint16_t w, h; tft->getTextBounds(tempText, 0, 0, &x1, &y1, &w, &h); tft->setCursor(LCD_CENTER_X - w/2, /*100*/ 115); tft->print(tempText); // زیرنویس دما /*tft->setFont(&FreeSansBold9pt7b); tft->setTextColor(COLOR_TEXT_DIM, COLOR_BG_DARK); String tempLabel = "Temperature"; tft->getTextBounds(tempLabel, 0, 0, &x1, &y1, &w, &h); tft->setCursor(LCD_CENTER_X - w/2, 140); tft->print(tempLabel);*/ // ========== نمایش پارامترها در چهار گوشه (داخل دایره) ========== tft->setFont(&FreeSansBold12pt7b); // گوشه بالا چپ: نور (L) - فاصله از لبه String lightText = "L:" + String((int)currentData.lightLux); if (currentData.lightLux > 9999) { lightText = "L:" + String(currentData.lightLux / 1000, 0) + "K"; } tft->getTextBounds(lightText, 0, 0, &x1, &y1, &w, &h); tft->setTextColor(COLOR_LIGHT, COLOR_BG_DARK); tft->setCursor(40, /*60*/ 140); // به سمت مرکز منتقل شد tft->print(lightText); // گوشه بالا راست: رطوبت (H) String humText = "H:" + String(currentData.humidity, 0) + "%"; tft->getTextBounds(humText, 0, 0, &x1, &y1, &w, &h); tft->setTextColor(COLOR_HUM, COLOR_BG_DARK); tft->setCursor(240 - w - 40, 140/*60*/); // به سمت مرکز منتقل شد tft->print(humText); // گوشه پایین چپ: باتری (B) String batText; if (currentData.power == 1) { batText = "P:ON"; tft->setTextColor(COLOR_POWER, COLOR_BG_DARK); } else { batText = "B:" + String(currentData.batteryPercent) + "%"; tft->setTextColor(COLOR_BATTERY, COLOR_BG_DARK); } tft->getTextBounds(batText, 0, 0, &x1, &y1, &w, &h); tft->setCursor(40, 180); // به سمت مرکز منتقل شد tft->print(batText); // گوشه پایین راست: گاز CO (G) bool gasWarning = currentData.coPPM > 50; String gasText = "G:" + String((int)currentData.coPPM); tft->getTextBounds(gasText, 0, 0, &x1, &y1, &w, &h); tft->setTextColor(gasWarning ? COLOR_TEMP : COLOR_GAS, COLOR_BG_DARK); tft->setCursor(240 - w - 40, 180); // به سمت مرکز منتقل شد tft->print(gasText); // ========== نمایش ولتاژ باتری در پایین مرکز ========== tft->setFont(&FreeSansBold9pt7b); String voltageText = String(currentData.batteryVoltage, 1) + "V"; tft->getTextBounds(voltageText, 0, 0, &x1, &y1, &w, &h); tft->setTextColor(COLOR_TEXT_DIM, COLOR_BG_DARK); tft->setCursor(LCD_CENTER_X - w/2, 210); // به بالا منتقل شد tft->print(voltageText); // ========== نمایش شناسه دستگاه کوچک در گوشه بالا مرکز ========== tft->setFont(&FreeSansBold9pt7b); tft->setTextColor(COLOR_TEXT_DIM, COLOR_BG_DARK); String idText = "#" + String(config.deviceId); tft->getTextBounds(idText, 0, 0, &x1, &y1, &w, &h); tft->setCursor(LCD_CENTER_X - w/2, 20); // به پایین منتقل شد tft->print(idText); } inline void displayAllParameters() { if (!tft) { Serial1.print("Not TFT!!"); return; } // پاک کردن صفحه tft->fillScreen(COLOR_BG_DARK); // ========== نمایش دما بزرگ در مرکز ========== String tempText = String(currentData.temperature, 1) + "°C"; tft->setFont(&FreeSansBold18pt7b); tft->setTextColor(COLOR_TEMP, COLOR_BG_DARK); int16_t x1, y1; uint16_t w, h; tft->getTextBounds(tempText, 0, 0, &x1, &y1, &w, &h); tft->setCursor(LCD_CENTER_X - w/2, 100); tft->print(tempText); // زیرنویس دما tft->setFont(&FreeSansBold9pt7b); tft->setTextColor(COLOR_TEXT_DIM, COLOR_BG_DARK); String tempLabel = "Temperature"; tft->getTextBounds(tempLabel, 0, 0, &x1, &y1, &w, &h); tft->setCursor(LCD_CENTER_X - w/2, 140); tft->print(tempLabel); // ========== نمایش پارامترها در چهار گوشه (داخل دایره) ========== tft->setFont(&FreeSansBold12pt7b); // گوشه بالا چپ: نور (L) - فاصله از لبه String lightText = "L:" + String((int)currentData.lightLux); if (currentData.lightLux > 9999) { lightText = "L:" + String(currentData.lightLux / 1000, 0) + "K"; } tft->getTextBounds(lightText, 0, 0, &x1, &y1, &w, &h); tft->setTextColor(COLOR_LIGHT, COLOR_BG_DARK); tft->setCursor(40, 60); // به سمت مرکز منتقل شد tft->print(lightText); // گوشه بالا راست: رطوبت (H) String humText = "H:" + String(currentData.humidity, 0) + "%"; tft->getTextBounds(humText, 0, 0, &x1, &y1, &w, &h); tft->setTextColor(COLOR_HUM, COLOR_BG_DARK); tft->setCursor(240 - w - 40, 60); // به سمت مرکز منتقل شد tft->print(humText); // گوشه پایین چپ: باتری (B) String batText; if (currentData.power == 1) { batText = "P:ON"; tft->setTextColor(COLOR_POWER, COLOR_BG_DARK); } else { batText = "B:" + String(currentData.batteryPercent) + "%"; tft->setTextColor(COLOR_BATTERY, COLOR_BG_DARK); } tft->getTextBounds(batText, 0, 0, &x1, &y1, &w, &h); tft->setCursor(40, 180); // به سمت مرکز منتقل شد tft->print(batText); // گوشه پایین راست: گاز CO (G) bool gasWarning = currentData.coPPM > 50; String gasText = "G:" + String((int)currentData.coPPM); tft->getTextBounds(gasText, 0, 0, &x1, &y1, &w, &h); tft->setTextColor(gasWarning ? COLOR_TEMP : COLOR_GAS, COLOR_BG_DARK); tft->setCursor(240 - w - 40, 180); // به سمت مرکز منتقل شد tft->print(gasText); // ========== نمایش ولتاژ باتری در پایین مرکز ========== tft->setFont(&FreeSansBold9pt7b); String voltageText = String(currentData.batteryVoltage, 1) + "V"; tft->getTextBounds(voltageText, 0, 0, &x1, &y1, &w, &h); tft->setTextColor(COLOR_TEXT_DIM, COLOR_BG_DARK); tft->setCursor(LCD_CENTER_X - w/2, 210); // به بالا منتقل شد tft->print(voltageText); // ========== نمایش شناسه دستگاه کوچک در گوشه بالا مرکز ========== tft->setFont(&FreeSansBold9pt7b); tft->setTextColor(COLOR_TEXT_DIM, COLOR_BG_DARK); String idText = "#" + String(config.deviceId); tft->getTextBounds(idText, 0, 0, &x1, &y1, &w, &h); tft->setCursor(LCD_CENTER_X - w/2, 20); // به پایین منتقل شد tft->print(idText); } // ==================== تابع آپدیت نمایشگر ==================== inline void updateDisplay() { if (!tft) { Serial1.print("Display not initialized!"); return; } // تغییر خودکار صفحه هر 15 ثانیه static int displayMode = 0; if (millis() - lastDisplayChange > 3000) { displayMode = (displayMode + 1) % 7; lastDisplayChange = millis(); } // نمایش بر اساس حالت if (displayMode < 6) { displayAllParameters(); //GdisplayAllParameters(); } else { displayAllParameters(); //GdisplayAllParameters(); //displaySimpleMode(); } } // ==================== تابع راه‌اندازی نمایشگر ==================== inline void initDisplay() { // ایجاد شیء نمایشگر Arduino_DataBus *bus = new Arduino_HWSPI(TFT_DC, TFT_CS, &SPI); tft = new Arduino_GC9A01(bus, -1, 0, true); // بدون پین RST // راه‌اندازی نمایشگر if (tft) { tft->begin(); tft->setRotation(1); // جهت نمایش tft->fillScreen(COLOR_BG_DARK); tft->setTextWrap(false); // تنظیم فونت پیش‌فرض tft->setFont(&FreeSansBold9pt7b); Serial1.println("Display initialized successfully"); } else { Serial1.println("Failed to initialize display"); } } #endif // DISPLAY_H