#include #include #include #include // Include the FastLED library #include "esp_sleep.h" // Include ESP-IDF deep sleep functions #include // Include WiFi library #include // Include PubSubClient library #include // Include ArduinoJson library for creating JSON (install via Library Manager) // Define the pins for our analog inputs const int colorSliderPin = 32; // ESP32 pin connected to the color slider (one pot) const int brightnessPotPin = 34; // ESP32 pin connected to the brightness potentiometer // Define the pins for our digital inputs (buttons) const int ttpButton0Pin = 27; // ESP32 pin connected to the HTTM Capacitive Button (On/Off) const int ttpButton1Pin = 26; // ESP32 pin connected to the TTP223 Touch Key Button (Target 1) const int ttpButton2Pin = 25; // ESP32 pin connected to the TTP223 Touch Key Button (Target 2) const int ttpButton3Pin = 4; // ESP32 pin connected to the TTP223 Touch Key Button (Target 3) const int ttpButton4Pin = 12; const int ttpButton5Pin = 15; // Define the OLED display parameters #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 32 // OLED display height, in pixels #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset) #define SCREEN_ADDRESS 0x3C // I2C address // Create an Adafruit_SSD1306 display object Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); // Define the FastLED parameters #define LED_PIN 13 // ESP32 pin connected to the LED strip data input #define NUM_LEDS 8 // Number of LEDs in your strip #define LED_TYPE WS2812B // Your LED strip type #define COLOR_ORDER GRB // Color order (often GRB for WS2812B) // Define the array of leds CRGB leds[NUM_LEDS]; // Variables to store button states int lastTtpButton0State = HIGH; int lastTtpButton1State = HIGH; int lastTtpButton2State = HIGH; int lastTtpButton3State = HIGH; int lastTtpButton4State = HIGH; int lastTtpButton5State = HIGH; // Variables to store current color and brightness values (RGB 0-255) - Global state int currentRed = 0; int currentGreen = 0; int currentBlue = 0; int currentBrightness = 0; // Brightness (0-255) - Global state // Variables to track the current range/section of analog inputs int currentColorRange = -1; // An index representing the current color/white section // Variables to store the last range/section that triggered a color update int lastUpdatedColorRange = -1; // Define the boundaries for color/white sections (adjust these based on your 2 white + 10 colors = 12 sections) // Assuming raw analog values from 0 to 4095 const int colorRangeBoundaries[] = { 0, // Start of Warm White Range (Range 0) 400, // End of Warm White Range, Start of Basic White Range (Range 1) 800, // End of Basic White Range, Start of Color 1 (Red) Range (Range 2) 1200, // End of Color 1, Start of Color 2 (Orange) Range (Range 3) 1600, // End of Color 2, Start of Color 3 (Yellow) Range (Range 4) 2000, // End of Color 3, Start of Color 4 (Green) Range (Range 5) 2400, // End of Color 4, Start of Color 5 (Blue) Range (Range 6) 2800, // End of Color 5, Start of Color 6 (Indigo) Range (Range 7) 3200, // End of Color 6, Start of Color 7 (Violet) Range (Range 8) 3600, // End of Color 7, Start of Color 8 Range (Range 9) 4000, // End of Color 8, Start of Color 9 Range (Range 10) 4096 // End of Color 9 Range (Range 11) - Use 4096 as the upper boundary of the last range }; const int numColorRanges = sizeof(colorRangeBoundaries) / sizeof(colorRangeBoundaries[0]) - 1; // Number of defined ranges (12 in this example) // Define the RGB values for the start of each color/white range // This array should have 'numColorRanges' number of entries struct ColorRange { int r, g, b; int colorTemp; }; // 3. Replace your existing color definitions with these: const ColorRange colorRangeRGB[] = { {255, 137, 14, 2200}, // Warm White - Very warm, cozy {255, 255, 255, 4000}, // Natural White - Clean, neutral {255, 0, 0, 2700}, // Red - Warm, rich {255, 165, 0, 3000}, // Orange - Warm, energetic {255, 255, 0, 3500}, // Yellow - Neutral warm {0, 255, 0, 5000}, // Green - Cool, natural {0, 0, 255, 6500}, // Blue - Cool, crisp {75, 0, 130, 6000}, // Indigo - Cool, deep {148, 0, 211, 5500}, // Violet - Cool, rich {255, 0, 127, 3200}, // Pink - Warm, vibrant {255, 193, 141, 2700}, // Warm Peach {255, 255, 224, 2500} // Light Warm }; // Variables for analog input debouncing and sleep timer unsigned long lastInteractionTime = 0; // Time of the last interaction (analog change or button press) const unsigned long analogSendDelay = 1000; // Delay in milliseconds before sending analog data after stabilization const unsigned long sleepDelay = 10000; // Delay in milliseconds before entering sleep (10 seconds) // Variable to store the currently selected light target (as an integer) int currentTargetIndex = 0; // 0: White Lamp, 1: Pink Lamp, 2: Desk Lamp // Array of target names corresponding to the integer index const char* targetNames[] = {"sam_bed", "jo_bed", "main_light","lounge_lights","all_lights"}; const char* displayNames[] = {"Sams Bed", "Joes Bed", "Main Light","Lounge Lights", "All Lights"}; const int numTargets = sizeof(targetNames) / sizeof(targetNames[0]); // Automatically calculate number of targets // RTC memory variables (will retain value during deep sleep) // We need to define these outside any function and use the RTC_DATA_ATTR macro RTC_DATA_ATTR int savedRed = 0; RTC_DATA_ATTR int savedGreen = 0; RTC_DATA_ATTR int savedBlue = 0; RTC_DATA_ATTR int savedBrightness = 0; RTC_DATA_ATTR int savedTargetIndex = 0; // Store the integer index in RTC memory RTC_DATA_ATTR bool savedLightStates[5] = {false, false, false, false, false}; // WiFi and MQTT credentials and topics const char* ssid = "Aussie Broadband 8729"; // Replace with your SSID const char* password = "Ffdfmunfca"; // Replace with your WiFi password const char* mqtt_server = "192.168.20.30"; // Replace with your MQTT broker IP/hostname const char* mqtt_user = "mqtt-user"; // Replace with your MQTT username (if any) const char* mqtt_password = "sam4jo"; // Replace with your MQTT password (if any) // MQTT Topics const char* mqtt_topic_publish = "homeassistant/lights/change"; // Topic to publish status FROM LoRa devices (we are sending control commands) // WiFi and MQTT client objects WiFiClient espClient; PubSubClient client(espClient); // Flag to track if a debounced analog update is pending MQTT send bool analogUpdatePendingSend = false; // Variables to store the last MAPPED analog values that were SENT via MQTT int lastSentRed = -1, lastSentGreen = -1, lastSentBlue = -1, lastSentBrightness = -1; unsigned long lastAnalogSendTime = 0; // Time the last analog MQTT message was sent // Variables to track the last RAW analog readings that caused a brightness update int lastUpdatedRawBrightness = -1; // Define the threshold for change in RAW brightness values const int rawBrightnessChangeThreshold = 60; // Example threshold, adjust as needed (4096 / 256 = 16 for 0-255 mapped steps) bool lightStates[5] = {false, false, false, false, false}; void setup() { delay(500); Serial.begin(115200); // Set pin modes for analog inputs pinMode(colorSliderPin, INPUT); pinMode(brightnessPotPin, INPUT); // Set pin modes for digital inputs (buttons) pinMode(ttpButton0Pin, INPUT_PULLUP); // HTTM button uses INPUT pinMode(ttpButton1Pin, INPUT_PULLUP); // TTP button likely needs pull-up pinMode(ttpButton2Pin, INPUT_PULLUP); // TTP button likely needs pull-up pinMode(ttpButton3Pin, INPUT_PULLUP); // TTP button likely needs pull-up pinMode(ttpButton4Pin, INPUT_PULLUP); // TTP button likely needs pull-up pinMode(ttpButton5Pin, INPUT_PULLUP); // TTP button likely needs pull-up // --- Configure Wake-up Sources --- const uint64_t wakeup_pin_mask = (1ULL << ttpButton0Pin) | (1ULL << ttpButton1Pin) | (1ULL << ttpButton2Pin) | (1ULL << ttpButton3Pin) | (1ULL << ttpButton4Pin) | (1ULL << ttpButton5Pin); // Using ANY_HIGH as it compiles in your environment esp_sleep_enable_ext1_wakeup(wakeup_pin_mask, ESP_EXT1_WAKEUP_ANY_HIGH); // --- Check Wake-up Cause --- esp_sleep_wakeup_cause_t wakeup_cause = esp_sleep_get_wakeup_cause(); if (wakeup_cause == ESP_SLEEP_WAKEUP_EXT1) { Serial.println("Wakeup cause: EXT1 (Button)"); for(int i = 0; i < 5; i++) { lightStates[i] = savedLightStates[i]; } // Restore state from RTC memory currentRed = savedRed; currentGreen = savedGreen; currentBlue = savedBlue; currentBrightness = savedBrightness; currentTargetIndex = savedTargetIndex; // Restore the integer index // Add a small delay after waking up to help prevent immediate re-triggering delay(100); } else if (wakeup_cause == ESP_SLEEP_WAKEUP_TIMER) { Serial.println("Wakeup cause: Timer"); } else { Serial.println("Wakeup cause: Other (e.g., Power On Reset)"); // Initialize state if not woken from sleep currentRed = 0; currentGreen = 0; currentBlue = 0; currentBrightness = 0; currentTargetIndex = 0; // Default to the first target (White Lamp) } // Initialize lastSentMapped values for fresh start or after restore lastSentRed = currentRed; lastSentGreen = currentGreen; lastSentBlue = currentBlue; lastSentBrightness = currentBrightness; Serial.println("Starting peripheral test..."); // Initialize the OLED display if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) { Serial.println(F("SSD1306 allocation failed")); for(;;); } display.clearDisplay(); display.display(); // Initialize the FastLED strip FastLED.addLeds(leds, NUM_LEDS).setCorrection(TypicalLEDStrip); // Set initial brightness based on restored/initial state FastLED.setBrightness(currentBrightness); // Set initial color based on restored/initial state CRGB initialColor = CRGB(currentRed, currentGreen, currentBlue); fill_solid(leds, NUM_LEDS, initialColor); FastLED.show(); // Turn off all pixels initially (or show restored state) // Set text size, color, and cursor position display.setTextSize(1); display.setTextColor(SSD1306_WHITE); display.setCursor(0,0); // Display initial message on the OLED including the target name display.println("Peripheral Test"); display.print("Target: "); display.println(displayNames[currentTargetIndex]); // Use the display name from the array display.println("Move controls"); display.println("Press buttons"); display.display(); // Initial display with restored state might take some time. // No delay needed here for the initial display. // Initialize lastInteractionTime to current time to prevent immediate sleep lastInteractionTime = millis(); // --- WiFi and MQTT Setup --- Serial.println("Connecting to WiFi..."); WiFi.begin(ssid, password); // Wait for WiFi connection (add a timeout in a real application) while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); client.setServer(mqtt_server, 1883); // Default MQTT port is 1883 // client.setCallback(callback); // Not needed for this application (only publishing) // Attempt to connect to MQTT broker reconnectMQTT(); } // Function to reconnect to MQTT broker void reconnectMQTT() { // Loop until we're reconnected while (!client.connected()) { Serial.print("Attempting MQTT connection..."); // Attempt to connect with authentication if (client.connect("ESP32Client", mqtt_user, mqtt_password)) { // Use a unique client ID Serial.println("connected"); // Subscribe to topics if needed (not needed for this project based on topics provided) // client.subscribe(mqtt_topic_subscribe); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" trying again in 5 seconds"); // Wait 5 seconds before retrying delay(5000); } } } // Function to publish MQTT message in JSON format void publishMQTT(int red, int green, int blue, int brightness, const char* targetName, const char* command = NULL) { if (!client.connected()) { reconnectMQTT(); } StaticJsonDocument<128> doc; if (command != NULL) { doc["command"] = command; } doc["target"] = targetName; if (command == NULL) { // Send both color_temp and xy coordinates doc["color_temp"] = colorRangeRGB[lastUpdatedColorRange].colorTemp; float x, y; RGBtoXY(red, green, blue, x, y); JsonArray xy_color = doc.createNestedArray("xy_color"); xy_color.add(x); xy_color.add(y); doc["brightness"] = brightness; doc["state"] = "ON"; // Update tracked state for(int i = 0; i < numTargets; i++) { if(strcmp(targetName, targetNames[i]) == 0) { lightStates[i] = true; break; } } } char jsonBuffer[128]; size_t jsonSize = serializeJson(doc, jsonBuffer); Serial.print("Attempting to publish JSON payload to topic: "); Serial.println(mqtt_topic_publish); Serial.print("Raw JSON payload ("); Serial.print(jsonSize); Serial.print(" bytes): ["); for (size_t i = 0; i < jsonSize; i++) { Serial.print(jsonBuffer[i]); } Serial.println("]"); if (client.publish(mqtt_topic_publish, (const byte*)jsonBuffer, jsonSize)) { Serial.println("MQTT message published successfully."); } else { Serial.println("MQTT message publishing failed."); } } void RGBtoXY(int r, int g, int b, float &x, float &y) { float red = r / 255.0f; float green = g / 255.0f; float blue = b / 255.0f; float X = red * 0.649926 + green * 0.103455 + blue * 0.197109; float Y = red * 0.234327 + green * 0.743075 + blue * 0.022598; float Z = red * 0.0000000 + green * 0.053077 + blue * 1.035763; float sum = X + Y + Z; if (sum > 0) { x = X / sum; y = Y / sum; } else { x = 0.312; y = 0.329; } } void loop() { if (!client.connected()) { reconnectMQTT(); // Ensure MQTT connection is maintained } client.loop(); // MQTT client loop to process incoming/outgoing messages // --- Read Raw Analog Values --- int rawColorValue = analogRead(colorSliderPin); int rawBrightnessValue = analogRead(brightnessPotPin); // --- Determine Current Color Range --- int newColorRange = -1; for (int i = 0; i < numColorRanges; i++) { if (rawColorValue >= colorRangeBoundaries[i] && rawColorValue < colorRangeBoundaries[i + 1]) { newColorRange = i; break; // Found the range, exit the loop } } // Handle the case where the value is at the very end of the range if (rawColorValue == 4095) { newColorRange = numColorRanges -1; // Assign to the last range } // --- Check for Color Range Change --- bool colorRangeChanged = false; if (newColorRange != lastUpdatedColorRange) { lastUpdatedColorRange = newColorRange; // Update the last updated range colorRangeChanged = true; Serial.print("Color Range Changed: "); Serial.println(newColorRange); // Update global color state to the RGB value for this range currentRed = colorRangeRGB[newColorRange].r; currentGreen = colorRangeRGB[newColorRange].g; currentBlue = colorRangeRGB[newColorRange].b; lastInteractionTime = millis(); // Reset timer on color range change } // --- Calculate Brightness --- int mappedBrightness = map(rawBrightnessValue, 0, 4095, 0, 255); // --- Check for Significant Brightness Change (Raw Value Threshold) --- // Use a threshold on the RAW brightness value to detect change static int lastRecordedRawBrightness = -1; // Store the last raw brightness value that caused an update bool brightnessValueChanged = false; if (lastRecordedRawBrightness == -1 || abs(rawBrightnessValue - lastRecordedRawBrightness) >= rawBrightnessChangeThreshold) { lastRecordedRawBrightness = rawBrightnessValue; // Record the raw value that caused this potential update // Only update the global brightness state if the mapped value is different (handles edge cases) Serial.print("Brightness (raw change): Raw="); // Modified print Serial.print(rawBrightnessValue); // Print the raw value Serial.print(" Mapped="); // Modified print Serial.println(currentBrightness); // Print the mapped value if (mappedBrightness != currentBrightness) { currentBrightness = mappedBrightness; // Update global brightness state brightnessValueChanged = true; lastInteractionTime = millis(); // Reset timer on brightness change Serial.print("Brightness (raw change): "); Serial.println(currentBrightness); } } // --- Update Display and LEDs if Color Range or Significant Brightness Changed --- if (colorRangeChanged || brightnessValueChanged) { // Update OLED Display with current state display.clearDisplay(); display.setCursor(0,0); display.setTextSize(1); display.println("Color/Brightness:"); display.print("R:"); display.print(currentRed); display.print(" G:"); display.print(currentGreen); display.print(" B:"); display.println(currentBlue); display.print("Brightness:"); display.println(currentBrightness); display.display(); // Update the LED strip color and brightness immediately for visual feedback CRGB targetColor = CRGB(currentRed, currentGreen, currentBlue); fill_solid(leds, NUM_LEDS, targetColor); FastLED.setBrightness(currentBrightness); FastLED.show(); } // --- Check for Debounced Analog Update and Send MQTT --- // This block sends data ONLY after a color range change OR a significant brightness change // AND enough time has passed since the last interaction. // The lastAnalogSendTime and lastSent values are global/static // --- Check for Debounced Analog Update and Send MQTT --- // This block sends data ONLY after a color range change OR a significant brightness change // AND enough time has passed since the last interaction. // The lastAnalogSendTime and lastSent values are global/static // We need a flag to indicate that an update is pending send static bool analogUpdatePendingSend = false; // This is already global, just for reference. // Set the pending send flag if a color range or brightness value changed if (colorRangeChanged || brightnessValueChanged) { analogUpdatePendingSend = true; // A change happened, mark for send } // Only attempt to send if an update is pending AND enough time has passed since the last Interaction. if (analogUpdatePendingSend && (millis() - lastInteractionTime >= analogSendDelay)) { // Check if the current global state is different from the last values that were ACTUALLY SENT. // lastSentRed, lastSentGreen, lastSentBlue, lastSentBrightness are global/static if (lastSentRed == -1 || // Handle the very first send currentRed != lastSentRed || currentGreen != lastSentGreen || currentBlue != lastSentBlue || currentBrightness != lastSentBrightness) { // If the state is different from the last sent state, publish Serial.println("Analog input stable (range/brightness change). Sending MQTT data."); publishMQTT(currentRed, currentGreen, currentBlue, currentBrightness, targetNames[currentTargetIndex]); // Update the last sent values lastSentRed = currentRed; lastSentGreen = currentGreen; lastSentBlue = currentBlue; lastSentBrightness = currentBrightness; lastAnalogSendTime = millis(); // Record the time of this send analogUpdatePendingSend = false; // Clear the pending send flag // No need to reset lastInteractionTime here, it was already reset when analogValueChanged was true } } // --- Read and Process Button States --- int currentTtpButton0State = digitalRead(ttpButton0Pin); int currentTtpButton1State = digitalRead(ttpButton1Pin); int currentTtpButton2State = digitalRead(ttpButton2Pin); int currentTtpButton3State = digitalRead(ttpButton3Pin); int currentTtpButton4State = digitalRead(ttpButton4Pin); int currentTtpButton5State = digitalRead(ttpButton5Pin); // Check if the HTTM button state has changed (On/Off) if (currentTtpButton0State != lastTtpButton0State) { delay(50); // Basic debounce delay if (currentTtpButton0State == LOW) { // Button is pressed Serial.println("POWER Button (On/Off) Pressed"); lastInteractionTime = millis(); // Reset sleep timer on button press lightStates[currentTargetIndex] = !lightStates[currentTargetIndex]; display.clearDisplay(); display.setCursor(0,0); display.setTextSize(2); display.println("On/Off Toggle"); display.display(); // ** Send MQTT message for On/Off toggle ** StaticJsonDocument<64> doc; // Smaller buffer for simple message doc["target"] = targetNames[currentTargetIndex]; // Use the target name from the array doc["command"] = "TOGGLE"; // Example command doc["command"] = lightStates[currentTargetIndex] ? "lights_on" : "lights_off"; char jsonBuffer[64]; serializeJson(doc, jsonBuffer); Serial.print("Publishing On/Off toggle for target: "); Serial.println(targetNames[currentTargetIndex]); Serial.println(jsonBuffer); client.publish(mqtt_topic_publish, (const byte*)jsonBuffer, strlen(jsonBuffer)); // Publish as bytes } else { Serial.println("HTTM Button (On/Off) Released"); } lastTtpButton0State = currentTtpButton0State; } // Check if TTP Button 1 (Target 1) state has changed if (currentTtpButton1State != lastTtpButton1State) { delay(50); // Basic debounce delay if (currentTtpButton1State == LOW) { // Button is pressed Serial.println("TTP Button 1 (Target 1) Pressed"); lastInteractionTime = millis(); // Reset sleep timer on button press currentTargetIndex = 0; // Set target index to 0 (White Lamp) display.clearDisplay(); display.setCursor(0,0); display.setTextSize(2); display.println(displayNames[currentTargetIndex]); // Display the name display.display(); Serial.print("Current Target Index: "); Serial.println(currentTargetIndex); // ** Send MQTT message indicating target change ** // StaticJsonDocument<64> doc; // doc["target"] = targetNames[currentTargetIndex]; // Use the target name from the array //doc["command"] = "SELECT_TARGET"; // Example command // char jsonBuffer[64]; // serializeJson(doc, jsonBuffer); // Serial.print("Publishing target change to: "); // Serial.println(targetNames[currentTargetIndex]); // Serial.println(jsonBuffer); // client.publish(mqtt_topic_publish, (const byte*)jsonBuffer, strlen(jsonBuffer)); // Publish as bytes } else { Serial.println("TTP Button 1 (Target 1) Released"); } lastTtpButton1State = currentTtpButton1State; } // Check if TTP Button 2 (Target 2) state has changed if (currentTtpButton2State != lastTtpButton2State) { delay(50); // Basic debounce delay if (currentTtpButton2State == LOW) { // Corrected variable name was 22 Serial.println("TTP Button 2 (Target 2) Pressed"); lastInteractionTime = millis(); // Reset sleep timer on button press currentTargetIndex = 1; // Set target index to 1 (Pink Lamp) display.clearDisplay(); display.setCursor(0,0); display.setTextSize(2); display.println(displayNames[currentTargetIndex]); // Display the name display.display(); Serial.print("Current Target Index: "); Serial.println(currentTargetIndex); // ** Send MQTT message indicating target change ** // StaticJsonDocument<64> doc; // doc["target"] = targetNames[currentTargetIndex]; // Use the target name from the array // doc["command"] = "SELECT_TARGET"; // Example command // char jsonBuffer[64]; // serializeJson(doc, jsonBuffer); // Serial.print("Publishing target change to: "); // Serial.println(targetNames[currentTargetIndex]); // Serial.println(jsonBuffer); // client.publish(mqtt_topic_publish, (const byte*)jsonBuffer, strlen(jsonBuffer)); // Publish as bytes } else { Serial.println("TTP Button 2 (Target 2) Released"); } lastTtpButton2State = currentTtpButton2State; } // Check if TTP Button 3 (Target 3) state has changed if (currentTtpButton3State != lastTtpButton3State) { delay(50); // Basic debounce delay if (currentTtpButton3State == LOW) { // Button is pressed Serial.println("TTP Button 3 (Target 3) Pressed"); lastInteractionTime = millis(); // Reset sleep timer on button press currentTargetIndex = 2; // Set target index to 2 (Desk Lamp) display.clearDisplay(); display.setCursor(0,0); display.setTextSize(2); display.println(displayNames[currentTargetIndex]); // Display the name display.display(); Serial.print("Current Target Index: "); Serial.println(currentTargetIndex); // ** Send MQTT message indicating target change ** // StaticJsonDocument<64> doc; // doc["target"] = targetNames[currentTargetIndex]; // Use the target name from the array // doc["command"] = "SELECT_TARGET"; // Example command // char jsonBuffer[64]; // serializeJson(doc, jsonBuffer); // Serial.print("Publishing target change to: "); // Serial.println(targetNames[currentTargetIndex]); // Serial.println(jsonBuffer); // client.publish(mqtt_topic_publish, (const byte*)jsonBuffer, strlen(jsonBuffer)); // Publish as bytes } else { Serial.println("TTP Button 3 (Target 3) Released"); } lastTtpButton3State = currentTtpButton3State; } // Check if TTP Button 4 (Target 4) state has changed if (currentTtpButton4State != lastTtpButton4State) { delay(50); // Basic debounce delay if (currentTtpButton4State == LOW) { // Button is pressed Serial.println("TTP Button 4 (Target 4) Pressed"); lastInteractionTime = millis(); // Reset sleep timer on button press currentTargetIndex = 3; // Set target index to 2 (Desk Lamp) display.clearDisplay(); display.setCursor(0,0); display.setTextSize(2); display.println(displayNames[currentTargetIndex]); // Display the name display.display(); Serial.print("Current Target Index: "); Serial.println(currentTargetIndex); // ** Send MQTT message indicating target change ** // StaticJsonDocument<64> doc; // doc["target"] = targetNames[currentTargetIndex]; // Use the target name from the array // doc["command"] = "SELECT_TARGET"; // Example command // char jsonBuffer[64]; // serializeJson(doc, jsonBuffer); // Serial.print("Publishing target change to: "); // Serial.println(targetNames[currentTargetIndex]); // Serial.println(jsonBuffer); // client.publish(mqtt_topic_publish, (const byte*)jsonBuffer, strlen(jsonBuffer)); // Publish as bytes } else { Serial.println("TTP Button 4 (Target 4) Released"); } lastTtpButton4State = currentTtpButton4State; } // Check if TTP Button 5 (Target 5) state has changed if (currentTtpButton5State != lastTtpButton5State) { delay(50); // Basic debounce delay if (currentTtpButton5State == LOW) { // Button is pressed Serial.println("TTP Button 5 (Target 5) Pressed"); lastInteractionTime = millis(); // Reset sleep timer on button press currentTargetIndex = 4; // Set target index to 2 (Desk Lamp) display.clearDisplay(); display.setCursor(0,0); display.setTextSize(2); display.println(displayNames[currentTargetIndex]); // Display the name display.display(); Serial.print("Current Target Index: "); Serial.println(currentTargetIndex); // ** Send MQTT message indicating target change ** // StaticJsonDocument<64> doc; // doc["target"] = targetNames[currentTargetIndex]; // Use the target name from the array // doc["command"] = "SELECT_TARGET"; // Example command // char jsonBuffer[64]; // serializeJson(doc, jsonBuffer); // Serial.print("Publishing target change to: "); // Serial.println(targetNames[currentTargetIndex]); // Serial.println(jsonBuffer); // client.publish(mqtt_topic_publish, (const byte*)jsonBuffer, strlen(jsonBuffer)); // Publish as bytes } else { Serial.println("TTP Button 5 (Target 5) Released"); } lastTtpButton5State = currentTtpButton5State; } // --- Check for Sleep Condition --- // If no interaction (analog change or button press) for sleepDelay if ((millis() - lastInteractionTime >= sleepDelay) && lastInteractionTime > 0) { Serial.println("Inactivity detected. Entering deep sleep..."); for(int i = 0; i < 5; i++) { savedLightStates[i] = lightStates[i]; } // Save current state to RTC memory before sleeping savedRed = currentRed; savedGreen = currentGreen; savedBlue = currentBlue; savedBrightness = currentBrightness; savedTargetIndex = currentTargetIndex; // Save the integer index display.clearDisplay(); // Clear display before sleeping display.display(); // Power down peripherals before sleeping to save power // For FastLED, setting brightness to 0 and showing is a good step for minimum power. FastLED.setBrightness(0); FastLED.show(); // Disconnect from WiFi and MQTT before sleeping WiFi.disconnect(true); client.disconnect(); Serial.println("Disconnected from WiFi and MQTT."); // Enter deep sleep, woken by button presses (ANY_HIGH) esp_deep_sleep_start(); // Corrected function name } // Small delay to keep the loop from running too fast when idle delay(10); }