commit d258de302d2ef49b7624fefd4595cbbaa93f3ac8 Author: Sam Date: Fri May 23 10:27:05 2025 +1000 Initial commit diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..b4f3380 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "Win32", + "includePath": [ + "${workspaceFolder}/**", + "C:/Users/Dell/Documents/Arduino/libraries/**", + "C:/Users/Dell/AppData/Local/Arduino15/packages/arduino/hardware/avr/1.8.6/cores/arduino" + ], + "defines": [ + "_DEBUG", + "UNICODE", + "_UNICODE" + ] + } + ], + "version": 4 +} \ No newline at end of file diff --git a/Light_Controller.ino b/Light_Controller.ino new file mode 100644 index 0000000..1b2f1f2 --- /dev/null +++ b/Light_Controller.ino @@ -0,0 +1,768 @@ +#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); +}