// #include <Adafruit_GFX.h>       // Core graphics library
// #include <SPI.h>
// #include <Wire.h>
// #include <Adafruit_ILI9341.h>   // Hardware-specific library
// #include <Adafruit_FT6206.h>
// #include "DHT.h"                // DHT sensor library
// #include <cmath>                // For round() and isnan()
// #include <Fonts/FreeSans24pt7b.h> // Custom Font for sensor values
// // #include <Fonts/FreeSans18pt7b.h> // Consider a slightly smaller font for target temp if 24pt is too large

// // Pin definitions
// #define TFT_CS    15
// #define TFT_DC    2
// #define TFT_RST   -1
// #define TOUCH_SCL 8
// #define TOUCH_SDA 10
// #define DHTPIN    17
// #define DHTTYPE   DHT22

// // Objects
// Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
// Adafruit_FT6206 touch = Adafruit_FT6206();
// DHT dht(DHTPIN, DHTTYPE);

// // --- Bitmaps ---
// static const unsigned char PROGMEM image_debug_on_bits[] = {
//     0x03,0xc0,0x12,0x48,0x2c,0x34,0x40,0x02,0x23,0xc4,0x24,0x24,0xc8,0x13,0x88,0x11,
//     0x88,0x11,0xc8,0x13,0x24,0x24,0x23,0xc4,0x40,0x02,0x2c,0x34,0x12,0x48,0x03,0xc0
// };
// #define DEBUG_ICON_W  16
// #define DEBUG_ICON_H  16

// static const unsigned char PROGMEM image_humidity_detail_bits[] = {
//     0x04,0x00,0x00,0x04,0x00,0x00,0x0c,0x00,0x00,0x0a,0x00,0x00,0x12,0x00,0x00,0x11,0x00,0x00,
//     0x20,0x80,0x00,0x20,0x80,0x00,0x41,0x40,0x00,0x40,0xc0,0x00,0x80,0xa0,0x00,0x80,0x20,0x00,
//     0x40,0x40,0x00,0x40,0x40,0x00,0x30,0x80,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
//     0x1c,0x08,0x00,0x76,0x10,0x00,0x63,0x10,0x00,0x63,0x20,0x00,0x63,0x20,0x00,0x36,0x40,0x00,
//     0x1c,0x80,0x00,0x00,0x9e,0x00,0x01,0x3b,0x80,0x01,0x31,0x80,0x02,0x31,0x80,0x02,0x3b,0x80,
//     0x04,0x1e,0x00
// };
// #define HUMIDITY_ICON_W 17
// #define HUMIDITY_ICON_H 31

// // --- ADDED: Temp Up/Down Bitmaps ---
// static const unsigned char PROGMEM image_temp_down_bits[] = {
//     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
//     0xff,0xff,0xff,0xff,0xff,0xfe,0x00,0x7f,0xfe,0x00,0x7f,0xff,0xff,0xff,0x7f,0xff,
//     0xfe,0x3f,0xff,0xfc,0x1f,0xff,0xf8,0x0f,0xff,0xf0,0x07,0xff,0xe0,0x03,0xff,0xc0,
//     0x01,0xff,0x80,0x00,0xff,0x00,0x00,0x7e,0x00,0x00,0x3c,0x00,0x00,0x18,0x00
// };
// static const unsigned char PROGMEM image_temp_up_bits[] = {
//     0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x3c,0x00,0x00,0x7e,0x00,0x00,0xff,0x00,0x01,
//     0xff,0x80,0x03,0xff,0xc0,0x07,0xe7,0xe0,0x0f,0xe7,0xf0,0x1f,0xe7,0xf8,0x3f,0xe7,
//     0xfc,0x7e,0x00,0x7e,0xfe,0x00,0x7f,0xff,0xe7,0xff,0xff,0xe7,0xff,0xff,0xe7,0xff,
//     0xff,0xe7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xfe
// };
// #define TEMP_ICON_W 24
// #define TEMP_ICON_H 21
// // ---

// // --- Layout Definitions ---
// // Debug Button Area
// #define DEBUG_BUTTON_RECT_X  5
// #define DEBUG_BUTTON_RECT_Y  201
// #define DEBUG_BUTTON_RECT_W  33
// #define DEBUG_BUTTON_RECT_H  33
// #define DEBUG_ICON_X  (DEBUG_BUTTON_RECT_X + (DEBUG_BUTTON_RECT_W - DEBUG_ICON_W) / 2)
// #define DEBUG_ICON_Y  (DEBUG_BUTTON_RECT_Y + (DEBUG_BUTTON_RECT_H - DEBUG_ICON_H) / 2)

// // Temperature Display Container
// #define CONTAINER_TEMP_X   43
// #define CONTAINER_TEMP_Y   11
// #define CONTAINER_TEMP_W   80
// #define CONTAINER_TEMP_H   36

// // Humidity Display Container
// #define CONTAINER_HUMID_X  43
// #define CONTAINER_HUMID_Y  194
// #define CONTAINER_HUMID_W  80
// #define CONTAINER_HUMID_H  36

// // Target Temperature Display Area (within inner circle)
// #define TARGET_CIRCLE_CENTER_X 178
// #define TARGET_CIRCLE_CENTER_Y 119
// #define TARGET_CIRCLE_INNER_R  84
// #define TARGET_TEXT_Y_POS      82 // As per user example drawString call

// // Target Temperature Control Buttons
// #define TEMP_UP_X 167 // Top-left X of UP bitmap
// #define TEMP_UP_Y 45  // Top-left Y of UP bitmap
// #define TEMP_DOWN_X 166 // Top-left X of DOWN bitmap
// #define TEMP_DOWN_Y 173 // Top-left Y of DOWN bitmap

// // Define Touch Areas slightly larger than icons for easier interaction
// #define TOUCH_AREA_PADDING 5
// #define TEMP_UP_RECT_X (TEMP_UP_X - TOUCH_AREA_PADDING)
// #define TEMP_UP_RECT_Y (TEMP_UP_Y - TOUCH_AREA_PADDING)
// #define TEMP_UP_RECT_W (TEMP_ICON_W + 2 * TOUCH_AREA_PADDING)
// #define TEMP_UP_RECT_H (TEMP_ICON_H + 2 * TOUCH_AREA_PADDING)

// #define TEMP_DOWN_RECT_X (TEMP_DOWN_X - TOUCH_AREA_PADDING)
// #define TEMP_DOWN_RECT_Y (TEMP_DOWN_Y - TOUCH_AREA_PADDING)
// #define TEMP_DOWN_RECT_W (TEMP_ICON_W + 2 * TOUCH_AREA_PADDING)
// #define TEMP_DOWN_RECT_H (TEMP_ICON_H + 2 * TOUCH_AREA_PADDING)
// // ---

// // --- Canvas Objects ---
// GFXcanvas1 tempCanvas(CONTAINER_TEMP_W, CONTAINER_TEMP_H);
// GFXcanvas1 humidCanvas(CONTAINER_HUMID_W, CONTAINER_HUMID_H);

// // --- Colors ---
// #define COLOR_DEBUG_ICON_ON    0x73AE
// #define COLOR_DEBUG_ICON_OFF   ILI9341_WHITE
// #define COLOR_BUTTON_RECT      ILI9341_WHITE
// #define COLOR_BORDER           ILI9341_WHITE
// #define COLOR_TEXT_SENSOR      ILI9341_WHITE // Color for current temp/humid text
// #define COLOR_TARGET_OUTER     ILI9341_WHITE
// #define COLOR_TARGET_INNER     ILI9341_BLACK
// #define COLOR_TEXT_TARGET      ILI9341_WHITE // Color for target temp text
// #define COLOR_TEMP_BUTTONS     ILI9341_WHITE // Color for up/down arrow icons
// #define COLOR_HUMIDITY_ICON    ILI9341_WHITE
// #define COLOR_BACKGROUND       ILI9341_BLACK
// #define COLOR_ERROR_TEXT       ILI9341_RED

// // --- State Variables ---
// bool thermostatActive = false; // Placeholder, functionality not fully implemented
// bool isThermostatInitialized = false;
// bool debugModeActive = false;

// // --- ADDED: Target Temperature Variables ---
// float targetTempC = 21.0f; // Default target temp
// const float MIN_TARGET_TEMP = 13.0f;
// const float MAX_TARGET_TEMP = 32.0f;
// const float TARGET_TEMP_INCREMENT = 1.0f;
// // ---

// // Timing variables
// unsigned long previousSensorMillis = 0;
// const long readInterval = 2000;

// // Debouncing Variables
// unsigned long lastDebounceTime = 0;
// unsigned long debounceDelay = 50;

// // --- Variables to store last displayed sensor values ---
// float lastDisplayedTempC = -999.0;
// float lastDisplayedHumidity = -999.0;

// // Text Buffers for Formatting
// char tempBuffer[10];
// char humidBuffer[8];
// char targetTempBuffer[8]; // ADDED buffer for target temp

// // Function Prototypes
// void drawStaticElements();
// void updateDebugButtonDisplay();
// void updateTemperatureDisplay(float tempC);
// void updateHumidityDisplay(float humidity);
// void updateTargetTempDisplay(); // ADDED prototype
// void readAndProcessSensors();

// // *** Function Implementations ***

// // Draws elements that don't change after initial setup
// void drawStaticElements() {
//     tft.fillScreen(COLOR_BACKGROUND);

//     // button_debug outline
//     tft.drawRoundRect(DEBUG_BUTTON_RECT_X, DEBUG_BUTTON_RECT_Y, DEBUG_BUTTON_RECT_W, DEBUG_BUTTON_RECT_H, 5, COLOR_BUTTON_RECT);

//     // target_container_outer
//     tft.fillCircle(TARGET_CIRCLE_CENTER_X, TARGET_CIRCLE_CENTER_Y, TARGET_CIRCLE_INNER_R + 5, COLOR_TARGET_OUTER); // Outer circle radius = inner + 5

//     // target_container_inner
//     tft.fillCircle(TARGET_CIRCLE_CENTER_X, TARGET_CIRCLE_CENTER_Y, TARGET_CIRCLE_INNER_R, COLOR_TARGET_INNER);

//     // --- ADDED: Temp Up/Down Icons ---
//     tft.drawBitmap(TEMP_UP_X, TEMP_UP_Y, image_temp_up_bits, TEMP_ICON_W, TEMP_ICON_H, COLOR_TEMP_BUTTONS);
//     tft.drawBitmap(TEMP_DOWN_X, TEMP_DOWN_Y, image_temp_down_bits, TEMP_ICON_W, TEMP_ICON_H, COLOR_TEMP_BUTTONS);
//     // ---

//     // humidity_detail icon (static position)
//     tft.drawBitmap(124, 198, image_humidity_detail_bits, HUMIDITY_ICON_W, HUMIDITY_ICON_H, COLOR_HUMIDITY_ICON);

//     // Other static buttons
//     tft.drawRoundRect(5, 5, 33, 33, 5, COLOR_BUTTON_RECT);   // button_mode
//     tft.drawRoundRect(5, 86, 33, 33, 5, COLOR_BUTTON_RECT);  // button_acfan
//     tft.drawRoundRect(5, 46, 33, 33, 5, COLOR_BUTTON_RECT);  // button_cf
//     tft.drawRoundRect(5, 163, 33, 33, 5, COLOR_BUTTON_RECT); // button_UNUSED
//     tft.drawRoundRect(5, 125, 33, 33, 5, COLOR_BUTTON_RECT); // button_UNUSED copy

//     // border
//     tft.drawRect(1, 1, tft.width() - 2, tft.height() - 2, COLOR_BORDER);
// }

// // Updates only the debug icon based on the current state
// void updateDebugButtonDisplay() {
//     uint16_t iconColor = debugModeActive ? COLOR_DEBUG_ICON_ON : COLOR_DEBUG_ICON_OFF;
//     tft.fillRect(DEBUG_ICON_X, DEBUG_ICON_Y, DEBUG_ICON_W, DEBUG_ICON_H, COLOR_BACKGROUND);
//     tft.drawBitmap(DEBUG_ICON_X, DEBUG_ICON_Y, image_debug_on_bits, DEBUG_ICON_W, DEBUG_ICON_H, iconColor);
// }

// // Updates the temperature display area using canvas
// void updateTemperatureDisplay(float tempC) {
//     int16_t x1, y1;
//     uint16_t w, h;

//     if (isnan(tempC)) { strcpy(tempBuffer, "---"); }
//     else { sprintf(tempBuffer, "%d", (int)round(tempC)); } // Format as integer

//     tempCanvas.setFont(&FreeSans24pt7b);
//     tempCanvas.setTextSize(1);
//     tempCanvas.setTextWrap(false);
//     tempCanvas.getTextBounds(tempBuffer, 0, 0, &x1, &y1, &w, &h);

//     int16_t startX_c = (CONTAINER_TEMP_W - 3) - w; // Right align in canvas w/ padding
//     int16_t startY_c = (CONTAINER_TEMP_H - h) / 2 - y1; // Vert center in canvas

//     tempCanvas.fillScreen(0); // Clear canvas (bg bit 0)
//     tempCanvas.setCursor(startX_c, startY_c);
//     tempCanvas.setTextColor(1); // Text bit 1
//     tempCanvas.print(tempBuffer);

//     tft.drawBitmap(CONTAINER_TEMP_X, CONTAINER_TEMP_Y, tempCanvas.getBuffer(),
//                    CONTAINER_TEMP_W, CONTAINER_TEMP_H, COLOR_TEXT_SENSOR, COLOR_BACKGROUND);

//     lastDisplayedTempC = tempC;
//     // Optional: Simplified debug output
//     // if (debugModeActive) Serial.printf("Updated Temp Canvas: %s C\n", tempBuffer);
// }

// // Updates the humidity display area using canvas
// void updateHumidityDisplay(float humidity) {
//     int16_t x1, y1;
//     uint16_t w, h;

//     if (isnan(humidity)) { strcpy(humidBuffer, "--"); }
//     else { sprintf(humidBuffer, "%.0f", humidity); } // Format as integer

//     humidCanvas.setFont(&FreeSans24pt7b);
//     humidCanvas.setTextSize(1);
//     humidCanvas.setTextWrap(false);
//     humidCanvas.getTextBounds(humidBuffer, 0, 0, &x1, &y1, &w, &h);

//     int16_t startX_c = (CONTAINER_HUMID_W - 3) - w; // Right align in canvas w/ padding
//     int16_t startY_c = (CONTAINER_HUMID_H - h) / 2 - y1; // Vert center in canvas

//     humidCanvas.fillScreen(0); // Clear canvas (bg bit 0)
//     humidCanvas.setCursor(startX_c, startY_c);
//     humidCanvas.setTextColor(1); // Text bit 1
//     humidCanvas.print(humidBuffer);

//     tft.drawBitmap(CONTAINER_HUMID_X, CONTAINER_HUMID_Y, humidCanvas.getBuffer(),
//                    CONTAINER_HUMID_W, CONTAINER_HUMID_H, COLOR_TEXT_SENSOR, COLOR_BACKGROUND);

//     lastDisplayedHumidity = humidity;
//     // Optional: Simplified debug output
//     // if (debugModeActive) Serial.printf("Updated Humid Canvas: %s %%\n", humidBuffer);
// }

// // // --- ADDED: Update Target Temperature Display ---
// // void updateTargetTempDisplay() {
// //     int16_t x1, y1;
// //     uint16_t w, h;

// //     // Format the target temp as a whole number
// //     int targetTempInt = round(targetTempC);
// //     sprintf(targetTempBuffer, "%d", targetTempInt);

// //     // Set font for target temp (using same font for consistency, adjust if needed)
// //     tft.setFont(&FreeSans24pt7b);
// //     tft.setTextSize(1); // Use size 1 with pt fonts

// //     // Get bounds to calculate horizontal centering
// //     tft.getTextBounds(targetTempBuffer, 0, 0, &x1, &y1, &w, &h);

// //     // Calculate X for horizontal centering within the inner circle area
// //     int16_t startX = TARGET_CIRCLE_CENTER_X - (w / 2);
// //     // Use the specified Y position
// //     int16_t startY = TARGET_TEXT_Y_POS;

// //     // Set text color with background color matching the inner circle
// //     // This overwrites previous text without needing explicit clearing
// //     tft.setTextColor(COLOR_TEXT_TARGET, COLOR_TARGET_INNER);

// //     // Draw the text
// //     tft.setCursor(startX, startY);
// //     tft.print(targetTempBuffer);

// //     if (debugModeActive) Serial.printf("Updated Target Temp Display: %s C (Cursor: x=%d, y=%d)\n", targetTempBuffer, startX, startY);
// // }
// // // ---

// // --- Updates Target Temperature Display (Centered Horizontally & Vertically) ---
// void updateTargetTempDisplay() {
//     int16_t x1, y1; // Vars for text bounding box relative offset
//     uint16_t w, h;  // Vars for text bounding box width and height

//     // Format the target temp as a whole number
//     int targetTempInt = round(targetTempC);
//     sprintf(targetTempBuffer, "%d", targetTempInt);

//     // Set font (ensure this is the font you want for the target temp)
//     tft.setFont(&FreeSans24pt7b);
//     tft.setTextSize(1); // Use size 1 with pt fonts

//     // Get bounds to calculate centering
//     tft.getTextBounds(targetTempBuffer, 0, 0, &x1, &y1, &w, &h);

//     // Calculate X for horizontal centering within the inner circle area
//     // Center of text's bounding box should align with circle center X
//     int16_t startX = TARGET_CIRCLE_CENTER_X - (w / 2);

//     // --- MODIFIED: Calculate Y for vertical centering ---
//     // Calculate starting Y (baseline) for vertical centering within the inner circle
//     // We want the center of the text's bounding box (h/2 from top) to align with the circle's center Y
//     // Baseline Y = CircleCenterY - (distance from baseline to box center)
//     // Baseline Y = CircleCenterY - (y1 + h/2)
//     // Simplified: Baseline Y = CircleCenterY - y1 - h/2
//     int16_t startY = TARGET_CIRCLE_CENTER_Y - y1 - (h / 2);
//     // ---

//     // Set text color with background color matching the inner circle
//     // This overwrites previous text without needing explicit clearing of the circle area
//     tft.setTextColor(COLOR_TEXT_TARGET, COLOR_TARGET_INNER);

//     // Draw the text
//     tft.setCursor(startX, startY); // Set cursor to calculated baseline position
//     tft.print(targetTempBuffer);

//     if (debugModeActive) Serial.printf("Updated Target Temp Display: %s C (Bounds: x1=%d, y1=%d, w=%d, h=%d | Cursor: x=%d, y=%d)\n",
//                                         targetTempBuffer, x1, y1, w, h, startX, startY);
// }

// // Reads sensors and updates respective displays (via canvas or directly)
// void readAndProcessSensors() {
//     float humidity = dht.readHumidity();
//     float temperatureCelsius = dht.readTemperature();

//     bool readError = isnan(humidity) || isnan(temperatureCelsius);

//     if (readError) {
//         if (debugModeActive) Serial.println("Failed to read from DHT sensor!");
//         updateTemperatureDisplay(NAN); // Update display with error via canvas
//         updateHumidityDisplay(NAN);    // Update display with error via canvas
//     } else {
//        if (debugModeActive) {
//             Serial.printf("Read: Temp=%.1fC, Hum=%.1f%% | Updating Sensor Displays\n",
//                         temperatureCelsius, humidity);
//         }
//         updateTemperatureDisplay(temperatureCelsius); // Update display via canvas
//         updateHumidityDisplay(humidity);           // Update display via canvas
//     }
// }


// // *** SETUP ***
// void setup() {
//     Serial.begin(115200);
//     delay(500);
//     Serial.println("\n---------------------------------");
//     Serial.println("System Starting...");

//     tft.begin();
//     tft.setRotation(3);
//     Serial.printf("TFT Initialized. Rotation: %d, Width: %d, Height: %d\n", tft.getRotation(), tft.width(), tft.height());

//     // Initialize Canvas Settings
//     tempCanvas.setFont(&FreeSans24pt7b);
//     tempCanvas.setTextWrap(false);
//     humidCanvas.setFont(&FreeSans24pt7b);
//     humidCanvas.setTextWrap(false);
//     Serial.println("Canvases initialized.");

//     // Initial screen drawing (static elements)
//     drawStaticElements();
//     Serial.println("Drew static elements.");

//     // Draw initial state of dynamic elements
//     updateDebugButtonDisplay();    // Initial debug icon state
//     updateTemperatureDisplay(NAN); // Initial sensor temp via canvas
//     updateHumidityDisplay(NAN);    // Initial sensor humid via canvas
//     updateTargetTempDisplay();     // ADDED: Initial target temp display
//     Serial.println("Drew initial dynamic elements.");

//     Serial.println("Initializing DHT sensor...");
//     dht.begin();
//     isThermostatInitialized = true;

//     Serial.println("Initializing Touchscreen...");
//     Wire.begin(TOUCH_SDA, TOUCH_SCL);
//     if (!touch.begin(40)) {
//         Serial.println("!!!!!! Touchscreen NOT FOUND! Check Wiring & I2C Address !!!!!!");
//         tft.setFont(); tft.setTextSize(2); tft.setTextColor(COLOR_ERROR_TEXT);
//         tft.setCursor(50, 100); tft.print("Touch Error!");
//         while (1) delay(100); // Halt
//     } else {
//         Serial.println("Touchscreen Initialized OK.");
//     }

//     Serial.println("Setup complete. Entering loop...");
//     Serial.println("---------------------------------");
//     previousSensorMillis = millis() - readInterval; // Force first sensor read soon
// }

// // *** LOOP ***
// void loop() {
//     unsigned long currentMillis = millis();

//     // --- Touch Handling ---
//     if (touch.touched()) {
//         if ((currentMillis - lastDebounceTime) > debounceDelay) {
//             TS_Point p = touch.getPoint();
//             int16_t touchX = tft.width() - 1 - p.y; // Map coords based on rotation
//             int16_t touchY = p.x;
//             bool touchHandled = false; // Flag to see if touch was processed

//             // Check Debug Button
//             if (!touchHandled &&
//                 (touchX >= DEBUG_BUTTON_RECT_X) && (touchX < (DEBUG_BUTTON_RECT_X + DEBUG_BUTTON_RECT_W)) &&
//                 (touchY >= DEBUG_BUTTON_RECT_Y) && (touchY < (DEBUG_BUTTON_RECT_Y + DEBUG_BUTTON_RECT_H)))
//             {
//                 Serial.printf("Touch Debug Btn (X=%d, Y=%d)\n", touchX, touchY);
//                 lastDebounceTime = currentMillis;
//                 debugModeActive = !debugModeActive;
//                 updateDebugButtonDisplay();
//                 touchHandled = true;
//                 if (debugModeActive) Serial.println("  Debug Mode ENABLED.");
//                 else Serial.println("  Debug Mode DISABLED.");
//             }

//             // Check Temp UP Button --- ADDED ---
//             if (!touchHandled &&
//                 (touchX >= TEMP_UP_RECT_X) && (touchX < (TEMP_UP_RECT_X + TEMP_UP_RECT_W)) &&
//                 (touchY >= TEMP_UP_RECT_Y) && (touchY < (TEMP_UP_RECT_Y + TEMP_UP_RECT_H)))
//             {
//                 Serial.printf("Touch Temp UP (X=%d, Y=%d)\n", touchX, touchY);
//                 lastDebounceTime = currentMillis;
//                 if (targetTempC < MAX_TARGET_TEMP) {
//                     targetTempC += TARGET_TEMP_INCREMENT;
//                     // Optional: Clamp to max after incrementing just in case of float issues
//                     if (targetTempC > MAX_TARGET_TEMP) targetTempC = MAX_TARGET_TEMP;
//                     updateTargetTempDisplay(); // Update screen
//                     Serial.printf("  Target Temp increased to: %.1f C\n", targetTempC);
//                 } else {
//                     Serial.println("  Target Temp already at MAX.");
//                 }
//                 touchHandled = true;
//             }

//             // Check Temp DOWN Button --- ADDED ---
//             if (!touchHandled &&
//                 (touchX >= TEMP_DOWN_RECT_X) && (touchX < (TEMP_DOWN_RECT_X + TEMP_DOWN_RECT_W)) &&
//                 (touchY >= TEMP_DOWN_RECT_Y) && (touchY < (TEMP_DOWN_RECT_Y + TEMP_DOWN_RECT_H)))
//              {
//                 Serial.printf("Touch Temp DOWN (X=%d, Y=%d)\n", touchX, touchY);
//                 lastDebounceTime = currentMillis;
//                  if (targetTempC > MIN_TARGET_TEMP) {
//                     targetTempC -= TARGET_TEMP_INCREMENT;
//                      // Optional: Clamp to min after decrementing
//                     if (targetTempC < MIN_TARGET_TEMP) targetTempC = MIN_TARGET_TEMP;
//                     updateTargetTempDisplay(); // Update screen
//                     Serial.printf("  Target Temp decreased to: %.1f C\n", targetTempC);
//                 } else {
//                      Serial.println("  Target Temp already at MIN.");
//                 }
//                 touchHandled = true;
//             }
//             // --- End Temp Button Checks ---

//             // Log if touch didn't hit any known active area
//             if (!touchHandled && debugModeActive) {
//                  Serial.printf("Touch Elsewhere (X=%d, Y=%d)\n", touchX, touchY);
//             }
//         } // End debounce check
//     } // End touch detected check


//     // --- Sensor Reading Logic ---
//     if (isThermostatInitialized && (currentMillis - previousSensorMillis >= readInterval)) {
//         previousSensorMillis = currentMillis;
//         readAndProcessSensors(); // Reads sensors and updates display via canvas functions
//     }
//     // --- End Sensor Reading Logic ---

//     // delay(10); // Optional small delay
// }













#include <Adafruit_GFX.h>       // Core graphics library
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_ILI9341.h>   // Hardware-specific library
#include <Adafruit_FT6206.h>
#include "DHT.h"                // DHT sensor library
#include <cmath>                // For round() and isnan()
#include <Fonts/FreeSans24pt7b.h> // Custom Font for sensor values

// Pin definitions
#define TFT_CS    15
#define TFT_DC    2
#define TFT_RST   -1
#define TOUCH_SCL 8
#define TOUCH_SDA 10
#define DHTPIN    17
#define DHTTYPE   DHT22

// Objects
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
Adafruit_FT6206 touch = Adafruit_FT6206();
DHT dht(DHTPIN, DHTTYPE);

// --- Bitmaps ---
static const unsigned char PROGMEM image_debug_on_bits[] = { /* ... bitmap data ... */
    0x03,0xc0,0x12,0x48,0x2c,0x34,0x40,0x02,0x23,0xc4,0x24,0x24,0xc8,0x13,0x88,0x11,
    0x88,0x11,0xc8,0x13,0x24,0x24,0x23,0xc4,0x40,0x02,0x2c,0x34,0x12,0x48,0x03,0xc0 };
#define DEBUG_ICON_W  16
#define DEBUG_ICON_H  16

static const unsigned char PROGMEM image_humidity_detail_bits[] = { /* ... bitmap data ... */
    0x04,0x00,0x00,0x04,0x00,0x00,0x0c,0x00,0x00,0x0a,0x00,0x00,0x12,0x00,0x00,0x11,0x00,0x00,
    0x20,0x80,0x00,0x20,0x80,0x00,0x41,0x40,0x00,0x40,0xc0,0x00,0x80,0xa0,0x00,0x80,0x20,0x00,
    0x40,0x40,0x00,0x40,0x40,0x00,0x30,0x80,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x1c,0x08,0x00,0x76,0x10,0x00,0x63,0x10,0x00,0x63,0x20,0x00,0x63,0x20,0x00,0x36,0x40,0x00,
    0x1c,0x80,0x00,0x00,0x9e,0x00,0x01,0x3b,0x80,0x01,0x31,0x80,0x02,0x31,0x80,0x02,0x3b,0x80,
    0x04,0x1e,0x00 };
#define HUMIDITY_ICON_W 17
#define HUMIDITY_ICON_H 31

static const unsigned char PROGMEM image_temp_down_bits[] = { /* ... bitmap data ... */
    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
    0xff,0xff,0xff,0xff,0xff,0xfe,0x00,0x7f,0xfe,0x00,0x7f,0xff,0xff,0xff,0x7f,0xff,
    0xfe,0x3f,0xff,0xfc,0x1f,0xff,0xf8,0x0f,0xff,0xf0,0x07,0xff,0xe0,0x03,0xff,0xc0,
    0x01,0xff,0x80,0x00,0xff,0x00,0x00,0x7e,0x00,0x00,0x3c,0x00,0x00,0x18,0x00 };
static const unsigned char PROGMEM image_temp_up_bits[] = { /* ... bitmap data ... */
    0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x3c,0x00,0x00,0x7e,0x00,0x00,0xff,0x00,0x01,
    0xff,0x80,0x03,0xff,0xc0,0x07,0xe7,0xe0,0x0f,0xe7,0xf0,0x1f,0xe7,0xf8,0x3f,0xe7,
    0xfc,0x7e,0x00,0x7e,0xfe,0x00,0x7f,0xff,0xe7,0xff,0xff,0xe7,0xff,0xff,0xe7,0xff,
    0xff,0xe7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xfe };
#define TEMP_ICON_W 24
#define TEMP_ICON_H 21

// --- ADDED: C/F Icon Bitmaps ---
static const unsigned char PROGMEM image_c_ico_bits[] = {
    0x70,0x00,0x00,0x88,0x00,0x00,0x88,0x00,0x00,0x88,0x00,0x00,0x70,0x00,0x00,0x00,
    0x7e,0x00,0x00,0xc3,0x00,0x01,0x81,0x80,0x01,0x01,0x80,0x03,0x00,0x00,0x03,0x00,
    0x00,0x03,0x00,0x00,0x03,0x00,0x00,0x03,0x01,0x80,0x01,0x01,0x80,0x01,0x83,0x00,
    0x00,0xc3,0x00,0x00,0x7c,0x00
};
#define C_ICON_W 17
#define C_ICON_H 18

static const unsigned char PROGMEM image_f_ico_bits[] = {
    0x70,0x00,0x88,0x00,0x88,0x00,0x88,0x00,0x70,0x00,0x01,0xfe,0x01,0x80,0x01,0x80,
    0x01,0x80,0x01,0x80,0x01,0x80,0x01,0xfc,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,
    0x01,0x80,0x01,0x80
};
#define F_ICON_W 15 // Note: F icon is narrower
#define F_ICON_H 18
// ---

// --- Layout Definitions ---
// Debug Button Area
#define DEBUG_BUTTON_RECT_X  5
#define DEBUG_BUTTON_RECT_Y  201
#define DEBUG_BUTTON_RECT_W  33
#define DEBUG_BUTTON_RECT_H  33
#define DEBUG_ICON_X  (DEBUG_BUTTON_RECT_X + (DEBUG_BUTTON_RECT_W - DEBUG_ICON_W) / 2)
#define DEBUG_ICON_Y  (DEBUG_BUTTON_RECT_Y + (DEBUG_BUTTON_RECT_H - DEBUG_ICON_H) / 2)

// C/F Toggle Button Area --- ADDED ---
#define BUTTON_CF_RECT_X   5
#define BUTTON_CF_RECT_Y   46
#define BUTTON_CF_RECT_W   33
#define BUTTON_CF_RECT_H   33
// Define a single position for the C/F icon, center it within the button area
#define UNIT_ICON_AREA_X   BUTTON_CF_RECT_X
#define UNIT_ICON_AREA_Y   BUTTON_CF_RECT_Y
#define UNIT_ICON_AREA_W   BUTTON_CF_RECT_W
#define UNIT_ICON_AREA_H   BUTTON_CF_RECT_H
// We will calculate the exact X,Y inside the update function based on icon width

// Temperature Display Container
#define CONTAINER_TEMP_X   43
#define CONTAINER_TEMP_Y   11
#define CONTAINER_TEMP_W   80
#define CONTAINER_TEMP_H   36

// Humidity Display Container
#define CONTAINER_HUMID_X  43
#define CONTAINER_HUMID_Y  194
#define CONTAINER_HUMID_W  80
#define CONTAINER_HUMID_H  36

// Target Temperature Display Area
#define TARGET_CIRCLE_CENTER_X 178
#define TARGET_CIRCLE_CENTER_Y 119
#define TARGET_CIRCLE_INNER_R  84

// Target Temperature Control Buttons
#define TEMP_UP_X 167
#define TEMP_UP_Y 45
#define TEMP_DOWN_X 166
#define TEMP_DOWN_Y 173
#define TOUCH_AREA_PADDING 5 // Make touch areas larger than icons
#define TEMP_UP_RECT_X (TEMP_UP_X - TOUCH_AREA_PADDING)
#define TEMP_UP_RECT_Y (TEMP_UP_Y - TOUCH_AREA_PADDING)
#define TEMP_UP_RECT_W (TEMP_ICON_W + 2 * TOUCH_AREA_PADDING)
#define TEMP_UP_RECT_H (TEMP_ICON_H + 2 * TOUCH_AREA_PADDING)
#define TEMP_DOWN_RECT_X (TEMP_DOWN_X - TOUCH_AREA_PADDING)
#define TEMP_DOWN_RECT_Y (TEMP_DOWN_Y - TOUCH_AREA_PADDING)
#define TEMP_DOWN_RECT_W (TEMP_ICON_W + 2 * TOUCH_AREA_PADDING)
#define TEMP_DOWN_RECT_H (TEMP_ICON_H + 2 * TOUCH_AREA_PADDING)

// --- Canvas Objects ---
GFXcanvas1 tempCanvas(CONTAINER_TEMP_W, CONTAINER_TEMP_H);
GFXcanvas1 humidCanvas(CONTAINER_HUMID_W, CONTAINER_HUMID_H);

// --- Colors ---
#define COLOR_DEBUG_ICON_ON    0x73AE
#define COLOR_DEBUG_ICON_OFF   ILI9341_WHITE
#define COLOR_BUTTON_RECT      ILI9341_WHITE
#define COLOR_BORDER           ILI9341_WHITE
#define COLOR_TEXT_SENSOR      ILI9341_WHITE
#define COLOR_TARGET_OUTER     ILI9341_WHITE
#define COLOR_TARGET_INNER     ILI9341_BLACK
#define COLOR_TEXT_TARGET      ILI9341_WHITE
#define COLOR_TEMP_BUTTONS     ILI9341_WHITE
#define COLOR_UNIT_ICON        ILI9341_WHITE // Color for C/F icon
#define COLOR_HUMIDITY_ICON    ILI9341_WHITE
#define COLOR_BACKGROUND       ILI9341_BLACK
#define COLOR_ERROR_TEXT       ILI9341_RED

// --- State Variables ---
bool thermostatActive = false;
bool isThermostatInitialized = false;
bool debugModeActive = false;
bool isCelsius = true; // ADDED: Temperature unit state (true=C, false=F)

// Target Temperature Variables
float targetTempC = 21.0f; // Always store target internally as Celsius
const float MIN_TARGET_TEMP = 12.8f;
const float MAX_TARGET_TEMP = 32.2f;
const float TARGET_TEMP_INCREMENT = 1.0f;

// Timing variables
unsigned long previousSensorMillis = 0;
const long readInterval = 2000;

// Debouncing Variables
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;

// Variables to store last displayed sensor values
float lastDisplayedTempC = NAN; // Initialize to NAN to force first update
float lastDisplayedHumidity = NAN;

// Text Buffers for Formatting
char tempBuffer[10];
char humidBuffer[8];
char targetTempBuffer[8];

// --- Function Prototypes ---
float convertToFahrenheit(float celsius); // ADDED
void drawStaticElements();
void updateDebugButtonDisplay();
void updateUnitIconDisplay(); // ADDED
void updateTemperatureDisplay(float tempC);
void updateHumidityDisplay(float humidity);
void updateTargetTempDisplay();
void readAndProcessSensors();

// *** Function Implementations ***

// --- ADDED: Celsius to Fahrenheit Conversion ---
float convertToFahrenheit(float celsius) {
  return (celsius * 1.8f) + 32.0f;
}

// Draws elements that don't change after initial setup
void drawStaticElements() {
    tft.fillScreen(COLOR_BACKGROUND);

    // button_debug outline
    tft.drawRoundRect(DEBUG_BUTTON_RECT_X, DEBUG_BUTTON_RECT_Y, DEBUG_BUTTON_RECT_W, DEBUG_BUTTON_RECT_H, 5, COLOR_BUTTON_RECT);

    // button_cf outline --- ADDED ---
    tft.drawRoundRect(BUTTON_CF_RECT_X, BUTTON_CF_RECT_Y, BUTTON_CF_RECT_W, BUTTON_CF_RECT_H, 5, COLOR_BUTTON_RECT);

    // target_container_outer
    tft.fillCircle(TARGET_CIRCLE_CENTER_X, TARGET_CIRCLE_CENTER_Y, TARGET_CIRCLE_INNER_R + 5, COLOR_TARGET_OUTER);

    // target_container_inner
    tft.fillCircle(TARGET_CIRCLE_CENTER_X, TARGET_CIRCLE_CENTER_Y, TARGET_CIRCLE_INNER_R, COLOR_TARGET_INNER);

    // Temp Up/Down Icons
    tft.drawBitmap(TEMP_UP_X, TEMP_UP_Y, image_temp_up_bits, TEMP_ICON_W, TEMP_ICON_H, COLOR_TEMP_BUTTONS);
    tft.drawBitmap(TEMP_DOWN_X, TEMP_DOWN_Y, image_temp_down_bits, TEMP_ICON_W, TEMP_ICON_H, COLOR_TEMP_BUTTONS);

    // humidity_detail icon
    tft.drawBitmap(124, 198, image_humidity_detail_bits, HUMIDITY_ICON_W, HUMIDITY_ICON_H, COLOR_HUMIDITY_ICON);

    // Other static buttons (Ensure no overlap with C/F button)
    tft.drawRoundRect(5, 5, 33, 33, 5, COLOR_BUTTON_RECT);   // button_mode
    tft.drawRoundRect(5, 86, 33, 33, 5, COLOR_BUTTON_RECT);  // button_acfan
    // tft.drawRoundRect(5, 46, 33, 33, 5, COLOR_BUTTON_RECT);  // button_cf is now drawn above
    tft.drawRoundRect(5, 163, 33, 33, 5, COLOR_BUTTON_RECT); // button_UNUSED
    tft.drawRoundRect(5, 125, 33, 33, 5, COLOR_BUTTON_RECT); // button_UNUSED copy

    // border
    tft.drawRect(1, 1, tft.width() - 2, tft.height() - 2, COLOR_BORDER);
}

// Updates only the debug icon based on the current state
void updateDebugButtonDisplay() {
    uint16_t iconColor = debugModeActive ? COLOR_DEBUG_ICON_ON : COLOR_DEBUG_ICON_OFF;
    tft.fillRect(DEBUG_ICON_X, DEBUG_ICON_Y, DEBUG_ICON_W, DEBUG_ICON_H, COLOR_BACKGROUND);
    tft.drawBitmap(DEBUG_ICON_X, DEBUG_ICON_Y, image_debug_on_bits, DEBUG_ICON_W, DEBUG_ICON_H, iconColor);
}

// --- ADDED: Updates the C/F Unit Icon ---
void updateUnitIconDisplay() {
    const unsigned char* iconBitmap;
    uint16_t iconW, iconH;

    if (isCelsius) {
        iconBitmap = image_c_ico_bits;
        iconW = C_ICON_W;
        iconH = C_ICON_H;
    } else {
        iconBitmap = image_f_ico_bits;
        iconW = F_ICON_W;
        iconH = F_ICON_H;
    }

    // Calculate position to center the icon within the button area
    uint16_t iconX = UNIT_ICON_AREA_X + (UNIT_ICON_AREA_W - iconW) / 2;
    uint16_t iconY = UNIT_ICON_AREA_Y + (UNIT_ICON_AREA_H - iconH) / 2;

    // Clear the button area behind the icon
    tft.fillRect(UNIT_ICON_AREA_X + 1, UNIT_ICON_AREA_Y + 1, UNIT_ICON_AREA_W - 2, UNIT_ICON_AREA_H - 2, COLOR_BACKGROUND);

    // Draw the selected icon
    tft.drawBitmap(iconX, iconY, iconBitmap, iconW, iconH, COLOR_UNIT_ICON);

    if (debugModeActive) Serial.printf("Drew Unit Icon: %s\n", isCelsius ? "Celsius" : "Fahrenheit");
}


// Updates the CURRENT temperature display area using canvas, respecting unit
void updateTemperatureDisplay(float tempC) {
    int16_t x1, y1;
    uint16_t w, h;
    int displayTempInt; // Integer value to display (either C or F)

    // Check if input is valid before proceeding
    if (isnan(tempC)) {
        strcpy(tempBuffer, "---");
    } else {
        // Convert to F if needed, then round for display
        if (isCelsius) {
            displayTempInt = round(tempC);
        } else {
            displayTempInt = round(convertToFahrenheit(tempC));
        }
        sprintf(tempBuffer, "%d", displayTempInt); // Format the integer
    }

    // --- Canvas Drawing ---
    tempCanvas.setFont(&FreeSans24pt7b);
    tempCanvas.setTextSize(1);
    tempCanvas.setTextWrap(false);
    tempCanvas.getTextBounds(tempBuffer, 0, 0, &x1, &y1, &w, &h);

    int16_t startX_c = (CONTAINER_TEMP_W - 3) - w; // Right align in canvas w/ padding
    int16_t startY_c = (CONTAINER_TEMP_H - h) / 2 - y1; // Vert center in canvas

    tempCanvas.fillScreen(0); // Clear canvas
    tempCanvas.setCursor(startX_c, startY_c);
    tempCanvas.setTextColor(1); // Text bit 1
    tempCanvas.print(tempBuffer);

    // --- Transfer Canvas to Screen ---
    tft.drawBitmap(CONTAINER_TEMP_X, CONTAINER_TEMP_Y, tempCanvas.getBuffer(),
                   CONTAINER_TEMP_W, CONTAINER_TEMP_H, COLOR_TEXT_SENSOR, COLOR_BACKGROUND);

    lastDisplayedTempC = tempC; // Store the last *valid Celsius* reading
    // Optional: More detailed debug output
    // if (debugModeActive) Serial.printf("Updated Current Temp Display: %s %s\n", tempBuffer, isCelsius ? "C" : "F");
}

// Updates the humidity display area using canvas (unaffected by C/F toggle)
void updateHumidityDisplay(float humidity) {
    int16_t x1, y1;
    uint16_t w, h;

    if (isnan(humidity)) { strcpy(humidBuffer, "--"); }
    else { sprintf(humidBuffer, "%.0f", humidity); }

    humidCanvas.setFont(&FreeSans24pt7b);
    humidCanvas.setTextSize(1);
    humidCanvas.setTextWrap(false);
    humidCanvas.getTextBounds(humidBuffer, 0, 0, &x1, &y1, &w, &h);

    int16_t startX_c = (CONTAINER_HUMID_W - 3) - w;
    int16_t startY_c = (CONTAINER_HUMID_H - h) / 2 - y1;

    humidCanvas.fillScreen(0);
    humidCanvas.setCursor(startX_c, startY_c);
    humidCanvas.setTextColor(1);
    humidCanvas.print(humidBuffer);

    tft.drawBitmap(CONTAINER_HUMID_X, CONTAINER_HUMID_Y, humidCanvas.getBuffer(),
                   CONTAINER_HUMID_W, CONTAINER_HUMID_H, COLOR_TEXT_SENSOR, COLOR_BACKGROUND);

    lastDisplayedHumidity = humidity;
    // if (debugModeActive) Serial.printf("Updated Humid Canvas: %s %%\n", humidBuffer);
}

// Updates Target Temperature Display (Centered, respects unit C/F)
void updateTargetTempDisplay() {
    int16_t x1, y1;
    uint16_t w, h;
    int displayTargetTempInt; // Integer value to display (C or F)

    // Convert the internally stored Celsius target temp if needed for display
    if (isCelsius) {
        displayTargetTempInt = round(targetTempC);
    } else {
        displayTargetTempInt = round(convertToFahrenheit(targetTempC));
    }
    sprintf(targetTempBuffer, "%d", displayTargetTempInt); // Format the integer

    // --- Drawing directly on TFT (no canvas needed for single static-ish element) ---
    tft.setFont(&FreeSans24pt7b);
    tft.setTextSize(2);
    tft.getTextBounds(targetTempBuffer, 0, 0, &x1, &y1, &w, &h);

    int16_t startX = TARGET_CIRCLE_CENTER_X - (w / 2); // Horiz center
    int16_t startY = TARGET_CIRCLE_CENTER_Y - y1 - (h / 2); // Vert center baseline

    // Set color with background to overwrite previous value
    tft.setTextColor(COLOR_TEXT_TARGET, COLOR_TARGET_INNER);

    tft.setCursor(startX, startY);
    tft.print(targetTempBuffer);

    if (debugModeActive) Serial.printf("Updated Target Temp Display: %s %s (Internal: %.1f C)\n",
                                        targetTempBuffer, isCelsius ? "C" : "F", targetTempC);
}

// Reads sensors and updates respective displays
void readAndProcessSensors() {
    // Read sensors (consider adding error handling / retry logic here if needed)
    float humidity = dht.readHumidity();
    float currentTemperatureC = dht.readTemperature(); // Get current temp in Celsius

    // Update humidity display (only depends on humidity reading)
    updateHumidityDisplay(humidity); // Handles isnan internally

    // Update current temperature display (depends on temp reading and isCelsius flag)
    updateTemperatureDisplay(currentTemperatureC); // Handles isnan internally

    // We stored the valid Celsius reading in lastDisplayedTempC inside updateTemperatureDisplay
    if (debugModeActive && !isnan(currentTemperatureC) && !isnan(humidity)) {
        Serial.printf("Sensor Read OK: Temp=%.1fC, Hum=%.1f%%\n", currentTemperatureC, humidity);
    } else if (debugModeActive && (isnan(currentTemperatureC) || isnan(humidity))) {
         Serial.println("Sensor Read Error!");
    }
}


// *** SETUP ***
void setup() {
    Serial.begin(115200);
    delay(500);
    Serial.println("\n---------------------------------");
    Serial.println("System Starting...");

    tft.begin();
    tft.setRotation(3);
    Serial.printf("TFT Initialized. Rotation: %d, Width: %d, Height: %d\n", tft.getRotation(), tft.width(), tft.height());

    // Initialize Canvas Settings
    tempCanvas.setFont(&FreeSans24pt7b); tempCanvas.setTextWrap(false);
    humidCanvas.setFont(&FreeSans24pt7b); humidCanvas.setTextWrap(false);
    Serial.println("Canvases initialized.");

    // Initial screen drawing (static elements)
    drawStaticElements();
    Serial.println("Drew static elements.");

    // Draw initial state of dynamic elements
    isCelsius = true; // Start in Celsius
    updateDebugButtonDisplay();
    updateUnitIconDisplay(); // ADDED: Draw initial unit icon (C)
    updateTemperatureDisplay(NAN); // Show "---" initially
    updateHumidityDisplay(NAN);    // Show "--" initially
    updateTargetTempDisplay();     // Show initial target temp (in C)
    Serial.println("Drew initial dynamic elements.");

    Serial.println("Initializing DHT sensor...");
    dht.begin();
    isThermostatInitialized = true;

    Serial.println("Initializing Touchscreen...");
    Wire.begin(TOUCH_SDA, TOUCH_SCL);
    if (!touch.begin(40)) {
        Serial.println("!!!!!! Touchscreen NOT FOUND!");
        tft.setFont(); tft.setTextSize(2); tft.setTextColor(COLOR_ERROR_TEXT);
        tft.setCursor(50, 100); tft.print("Touch Error!");
        while (1) delay(100); // Halt
    } else {
        Serial.println("Touchscreen Initialized OK.");
    }

    Serial.println("Setup complete. Entering loop...");
    Serial.println("---------------------------------");
    previousSensorMillis = millis() - readInterval; // Force first sensor read soon
}

// *** LOOP ***
void loop() {
    unsigned long currentMillis = millis();

    // --- Touch Handling ---
    if (touch.touched()) {
        if ((currentMillis - lastDebounceTime) > debounceDelay) {
            TS_Point p = touch.getPoint();
            int16_t touchX = tft.width() - 1 - p.y; // Map coords
            int16_t touchY = p.x;
            bool touchHandled = false;

            // Check Debug Button
            if (!touchHandled &&
                (touchX >= DEBUG_BUTTON_RECT_X) && (touchX < (DEBUG_BUTTON_RECT_X + DEBUG_BUTTON_RECT_W)) &&
                (touchY >= DEBUG_BUTTON_RECT_Y) && (touchY < (DEBUG_BUTTON_RECT_Y + DEBUG_BUTTON_RECT_H)))
            {
                // ... (debug button logic as before) ...
                Serial.printf("Touch Debug Btn (X=%d, Y=%d)\n", touchX, touchY);
                lastDebounceTime = currentMillis;
                debugModeActive = !debugModeActive;
                updateDebugButtonDisplay();
                touchHandled = true;
                if (debugModeActive) Serial.println("  Debug Mode ENABLED.");
                else Serial.println("  Debug Mode DISABLED.");
            }

            // Check C/F Toggle Button --- ADDED ---
            if (!touchHandled &&
                (touchX >= BUTTON_CF_RECT_X) && (touchX < (BUTTON_CF_RECT_X + BUTTON_CF_RECT_W)) &&
                (touchY >= BUTTON_CF_RECT_Y) && (touchY < (BUTTON_CF_RECT_Y + BUTTON_CF_RECT_H)))
            {
                Serial.printf("Touch C/F Toggle (X=%d, Y=%d)\n", touchX, touchY);
                lastDebounceTime = currentMillis;
                isCelsius = !isCelsius; // Toggle the state
                updateUnitIconDisplay(); // Update the icon display
                // Force redraw of temperature displays with the new unit
                updateTemperatureDisplay(lastDisplayedTempC); // Use last valid C reading
                updateTargetTempDisplay(); // Update target display
                touchHandled = true;
                 Serial.printf("  Temperature Unit changed to: %s\n", isCelsius ? "Celsius" : "Fahrenheit");
            }

            // Check Temp UP Button
            if (!touchHandled &&
                (touchX >= TEMP_UP_RECT_X) && (touchX < (TEMP_UP_RECT_X + TEMP_UP_RECT_W)) &&
                (touchY >= TEMP_UP_RECT_Y) && (touchY < (TEMP_UP_RECT_Y + TEMP_UP_RECT_H)))
            {
                Serial.printf("Touch Temp UP (X=%d, Y=%d)\n", touchX, touchY);
                lastDebounceTime = currentMillis;
                // Logic always uses internal Celsius value
                if (targetTempC < MAX_TARGET_TEMP) {
                    targetTempC += TARGET_TEMP_INCREMENT;
                    if (targetTempC > MAX_TARGET_TEMP) targetTempC = MAX_TARGET_TEMP; // Clamp
                    updateTargetTempDisplay(); // Update screen (will display C or F based on isCelsius)
                    Serial.printf("  Target Temp increased to: %.1f C\n", targetTempC);
                } else {
                    Serial.println("  Target Temp already at MAX.");
                }
                touchHandled = true;
            }

            // Check Temp DOWN Button
            if (!touchHandled &&
                (touchX >= TEMP_DOWN_RECT_X) && (touchX < (TEMP_DOWN_RECT_X + TEMP_DOWN_RECT_W)) &&
                (touchY >= TEMP_DOWN_RECT_Y) && (touchY < (TEMP_DOWN_RECT_Y + TEMP_DOWN_RECT_H)))
             {
                Serial.printf("Touch Temp DOWN (X=%d, Y=%d)\n", touchX, touchY);
                lastDebounceTime = currentMillis;
                 // Logic always uses internal Celsius value
                 if (targetTempC > MIN_TARGET_TEMP) {
                    targetTempC -= TARGET_TEMP_INCREMENT;
                    if (targetTempC < MIN_TARGET_TEMP) targetTempC = MIN_TARGET_TEMP; // Clamp
                    updateTargetTempDisplay(); // Update screen (will display C or F based on isCelsius)
                    Serial.printf("  Target Temp decreased to: %.1f C\n", targetTempC);
                } else {
                     Serial.println("  Target Temp already at MIN.");
                }
                touchHandled = true;
            }

            // Log unhandled touches
            if (!touchHandled && debugModeActive) {
                 Serial.printf("Touch Elsewhere (X=%d, Y=%d)\n", touchX, touchY);
            }
        } // End debounce check
    } // End touch detected check


    // --- Sensor Reading Logic ---
    if (isThermostatInitialized && (currentMillis - previousSensorMillis >= readInterval)) {
        previousSensorMillis = currentMillis;
        readAndProcessSensors(); // Reads sensors and updates displays
    }
    // --- End Sensor Reading Logic ---

    // delay(10); // Optional small delay
}
Loading
esp32-s3-devkitc-1
Loading
ili9341-cap-touch
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module