Compare commits
2 Commits
3667ac3b8b
...
19ec9fca84
| Author | SHA1 | Date | |
|---|---|---|---|
| 19ec9fca84 | |||
| d258de302d |
18
.vscode/c_cpp_properties.json
vendored
Normal file
18
.vscode/c_cpp_properties.json
vendored
Normal file
@ -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
|
||||||
|
}
|
||||||
768
Light_Controller.ino
Normal file
768
Light_Controller.ino
Normal file
@ -0,0 +1,768 @@
|
|||||||
|
#include <Wire.h>
|
||||||
|
#include <Adafruit_GFX.h>
|
||||||
|
#include <Adafruit_SSD1306.h>
|
||||||
|
#include <FastLED.h> // Include the FastLED library
|
||||||
|
#include "esp_sleep.h" // Include ESP-IDF deep sleep functions
|
||||||
|
#include <WiFi.h> // Include WiFi library
|
||||||
|
#include <PubSubClient.h> // Include PubSubClient library
|
||||||
|
#include <ArduinoJson.h> // 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<LED_TYPE, LED_PIN, COLOR_ORDER>(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);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user