├── ColorReplica ├── colorpicker.h ├── reciver.h ├── reciver.cpp ├── icon.h ├── colorpicker.cpp └── ColorReplica.ino ├── LICENSE ├── README.md └── sender └── sender.ino /ColorReplica/colorpicker.h: -------------------------------------------------------------------------------- 1 | /* ____________________________ 2 | This software is licensed under the MIT License: 3 | https://github.com/cifertech/ColorReplica 4 | ________________________________________ */ 5 | 6 | #ifndef colorpicker_H 7 | #define colorpicker_H 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | void colorpickerSetup(); 14 | void colorpickerLoop(); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /ColorReplica/reciver.h: -------------------------------------------------------------------------------- 1 | /* ____________________________ 2 | This software is licensed under the MIT License: 3 | https://github.com/cifertech/ColorReplica 4 | ________________________________________ */ 5 | 6 | #ifndef reciver_H 7 | #define reciver_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | void reciverSetup(); 16 | void reciverLoop(); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 CiferTech 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | logo 4 |

ColorReplica

5 | 6 |

7 | RealTime Color Simulator 8 |

9 | 10 | 11 | 12 | 13 | 14 | cifertech - ColorReplica 15 | stars - ColorReplica 16 | forks - ColorReplica 17 | 18 |

19 | TWITTER 20 | · 21 | INSTAGRAM 22 | · 23 | YOUTUBE 24 | · 25 | WEBSITE 26 |

27 |
28 | 29 |
30 | 31 | 32 | ## 📖 Explore the Full Documentation 33 | 34 | Ready to dive deeper into our project's details? Discover the full story, in-depth tutorials, and all the exciting features in our comprehensive [documentation](https://cifertech.net/your-wireless-toolkit-for-color-replication/). Click the link and explore further! 35 | 36 | 37 | 38 | ## :star2: About the Project 39 | ColorReplica is an exciting project that allows you to explore and interact with colors in two unique ways: ColorPicker and ColorCube. Whether you're an artist, a DIY enthusiast, or just someone who appreciates the beauty of colors. 40 | 41 | 42 | 43 |
44 | screenshot 45 |
46 | 47 | 48 | 49 | ## :dart: Features 50 | 51 | ### ColorPicker 52 | ColorPicker is your palette of colors. With this feature, you can: 53 | 54 | Choose from a wide range of colors, letting your creativity run wild. 55 | Adjust the brightness of your chosen colors to set the perfect mood. 56 | Use user-friendly controls for an intuitive experience. 57 | 58 | ### ColorCube 59 | ColorCube brings color detection and replication to the forefront. It allows you to: 60 | 61 | Detect the colors of objects using the TCS34725 RGB sensor. 62 | Transmit color information to the main device. 63 | Replicate the detected color using WS2812B LEDs. 64 | Display color values in RGB, HSV, and HEX for your reference. 65 | 66 | 67 | 68 | ## :warning: License 69 | 70 | Distributed under the MIT License. See LICENSE.txt for more information. 71 | 72 | 73 | 74 | ## :handshake: Contact 75 | 76 | CiferTech - [@twitter](https://twitter.com/cifertech1) - CiferTech@gmali.com 77 | 78 | Project Link: [https://github.com/cifertech/ColorReplica](https://github.com/cifertech/ColorReplica) 79 | 80 | 81 | ## :gem: Acknowledgements 82 | 83 | - [Arduino OLED Menu](https://github.com/upiir/arduino_oled_menu) 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /sender/sender.ino: -------------------------------------------------------------------------------- 1 | /* ____________________________ 2 | This software is licensed under the MIT License: 3 | https://github.com/cifertech/ColorReplica 4 | ________________________________________ */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include "Adafruit_TCS34725.h" 11 | 12 | Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_614MS, TCS34725_GAIN_1X); 13 | 14 | uint8_t broadcastAddress[] = {0x0C, 0xDC, 0x7E, 0xE9, 0x33, 0x58}; 15 | 16 | #define BOARD_ID 1 17 | 18 | typedef struct struct_message { 19 | int r; 20 | int g; 21 | int b; 22 | int c; 23 | int ct; 24 | int lx; 25 | } struct_message; 26 | 27 | struct_message myData; 28 | 29 | unsigned long lastTime = 0; 30 | unsigned long timerDelay = 10000; 31 | 32 | const int buttonPin = 3; // Change to the pin you have your button connected to 33 | int buttonState = 0; 34 | int lastButtonState = HIGH; 35 | unsigned long lastDebounceTime = 0; 36 | unsigned long debounceDelay = 50; 37 | 38 | void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) { 39 | Serial.print("\r\nLast Packet Send Status: "); 40 | 41 | if (sendStatus == 0) { 42 | Serial.println("Delivery success"); 43 | } else { 44 | Serial.println("Delivery fail"); 45 | } 46 | } 47 | 48 | void setup() { 49 | Serial.begin(115200); 50 | 51 | WiFi.mode(WIFI_STA); 52 | WiFi.disconnect(); 53 | 54 | pinMode(buttonPin, INPUT_PULLUP); 55 | 56 | if (esp_now_init() != 0) { 57 | Serial.println("Error initializing ESP-NOW"); 58 | return; 59 | } 60 | esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER); 61 | esp_now_register_send_cb(OnDataSent); 62 | esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0); 63 | 64 | if (tcs.begin()) { 65 | Serial.println("Found sensor"); 66 | } else { 67 | Serial.println("No TCS34725 found ... check your connections"); 68 | while (1); 69 | } 70 | } 71 | 72 | void loop() { 73 | uint16_t r, g, b, c, colorTemp, lux; 74 | 75 | tcs.getRawData(&r, &g, &b, &c); 76 | colorTemp = tcs.calculateColorTemperature_dn40(r, g, b, c); 77 | lux = tcs.calculateLux(r, g, b); 78 | 79 | // Normalize the values 80 | float normalizedRed = (float)r / c; 81 | float normalizedGreen = (float)g / c; 82 | float normalizedBlue = (float)b / c; 83 | 84 | // Scale the normalized values to 0-255 85 | uint8_t scaledRed = normalizedRed * 255; 86 | uint8_t scaledGreen = normalizedGreen * 255; 87 | uint8_t scaledBlue = normalizedBlue * 255; 88 | 89 | buttonState = digitalRead(buttonPin); 90 | 91 | if (buttonState == LOW) { 92 | // Button is pressed, send data 93 | myData.r = scaledRed; 94 | myData.g = scaledGreen; 95 | myData.b = scaledBlue; 96 | myData.c = c; 97 | myData.ct = colorTemp; 98 | myData.lx = lux; 99 | 100 | esp_now_send(0, (uint8_t *)&myData, sizeof(myData)); 101 | 102 | 103 | 104 | if ((millis() - lastTime) > timerDelay) { 105 | // Send data periodically as before 106 | myData.r = scaledRed; 107 | myData.g = scaledGreen; 108 | myData.b = scaledBlue; 109 | myData.c = c; 110 | myData.ct = colorTemp; 111 | myData.lx = lux; 112 | 113 | esp_now_send(0, (uint8_t *)&myData, sizeof(myData)); 114 | lastTime = millis(); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /ColorReplica/reciver.cpp: -------------------------------------------------------------------------------- 1 | /* ____________________________ 2 | This software is licensed under the MIT License: 3 | https://github.com/cifertech/ColorReplica 4 | ________________________________________ */ 5 | 6 | #include 7 | #include "reciver.h" 8 | 9 | #define PIN 23 10 | #define NUM_PIXELS 18 11 | 12 | typedef struct struct_message { 13 | int r; 14 | int g; 15 | int b; 16 | int c; 17 | int ct; 18 | int lx; 19 | } struct_message; 20 | 21 | 22 | struct_message myData; 23 | 24 | extern U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2; 25 | 26 | extern Adafruit_NeoPixel strip; 27 | 28 | void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) { 29 | memcpy(&myData, incomingData, sizeof(myData)); 30 | Serial.print("Bytes received: "); 31 | Serial.println(len); 32 | Serial.print("R: "); 33 | Serial.println(myData.r); 34 | Serial.print("G: "); 35 | Serial.println(myData.g); 36 | Serial.print("B: "); 37 | Serial.println(myData.b); 38 | Serial.print("colorTemp: "); 39 | Serial.println(myData.ct); 40 | Serial.print("lux: "); 41 | Serial.println(myData.lx); 42 | Serial.println(); 43 | } 44 | 45 | void reciverSetup() { 46 | 47 | Serial.begin(115200); 48 | 49 | WiFi.mode(WIFI_STA); 50 | 51 | strip.begin(); 52 | strip.show(); 53 | 54 | u8g2.begin(); 55 | 56 | if (esp_now_init() != ESP_OK) { 57 | Serial.println("Error initializing ESP-NOW"); 58 | return; 59 | } 60 | esp_now_register_recv_cb(OnDataRecv); 61 | } 62 | 63 | void reciverLoop() { 64 | 65 | int r = myData.r; 66 | int g = myData.g; 67 | int b = myData.b; 68 | 69 | unsigned long hexColor = (unsigned long)r << 16 | (unsigned long)g << 8 | b; 70 | String hexColorStr = String("#" + String(hexColor, HEX)); 71 | 72 | Serial.println("RGB: (" + String(r) + ", " + String(g) + ", " + String(b) + ")"); 73 | Serial.println("HEX Color Code: " + hexColorStr); 74 | 75 | 76 | float R = r / 255.0; 77 | float G = g / 255.0; 78 | float B = b / 255.0; 79 | 80 | float maxVal = max(max(R, G), B); 81 | float minVal = min(min(R, G), B); 82 | 83 | float V = maxVal; 84 | float S = (maxVal == 0) ? 0 : (maxVal - minVal) / maxVal; 85 | 86 | float H; 87 | if (maxVal == R) { 88 | H = 60 * ((G - B) / (maxVal - minVal)) + 360; 89 | } else if (maxVal == G) { 90 | H = 60 * ((B - R) / (maxVal - minVal)) + 120; 91 | } else { 92 | H = 60 * ((R - G) / (maxVal - minVal)) + 240; 93 | } 94 | 95 | H = fmod(H, 360.0); 96 | 97 | Serial.println(" HSV: (" + String(H) + ", " + String(S) + ", " + String(V) + ")"); 98 | 99 | 100 | u8g2.clearBuffer(); 101 | u8g2.setFont(u8g_font_7x14B); 102 | u8g2.drawStr(0, 10, "RGB:"); 103 | u8g2.drawStr(0, 30, "HEX:"); 104 | u8g2.drawStr(0, 50, "HSV:"); 105 | u8g2.setCursor(30, 10); 106 | u8g2.print(myData.r); 107 | u8g2.print(","); 108 | u8g2.print(myData.g); 109 | u8g2.print(","); 110 | u8g2.println(myData.b); 111 | u8g2.setCursor(30, 30); 112 | u8g2.print(hexColorStr); 113 | u8g2.setFont(u8g2_font_6x10_tf); 114 | u8g2.setCursor(30, 50); 115 | u8g2.print(String(H)); 116 | u8g2.print(","); 117 | u8g2.print(String(S)); 118 | u8g2.print(","); 119 | u8g2.println(String(V)); 120 | u8g2.sendBuffer(); 121 | 122 | for (int i = 0; i < NUM_PIXELS; i++) { 123 | strip.setPixelColor(i, myData.r, myData.g, myData.b); 124 | } 125 | strip.show(); 126 | } 127 | -------------------------------------------------------------------------------- /ColorReplica/icon.h: -------------------------------------------------------------------------------- 1 | /* ____________________________ 2 | This software is licensed under the MIT License: 3 | https://github.com/cifertech/ColorReplica 4 | ________________________________________ */ 5 | 6 | // 'icon_colorcube', 16x16px 7 | const unsigned char bitmap_icon_colorcube [] PROGMEM = { 8 | 0x80, 0x01, 0xe0, 0x06, 0x98, 0x18, 0x86, 0x60, 0x82, 0x40, 0x82, 0x40, 0x82, 0x40, 0x82, 0x40, 9 | 0x82, 0x40, 0x82, 0x40, 0x82, 0x40, 0x86, 0x60, 0x98, 0x18, 0xe0, 0x06, 0x80, 0x01, 0x00, 0x00 }; 10 | 11 | // 'icon_colorpicker', 16x16px 12 | const unsigned char bitmap_icon_colorpicker [] PROGMEM = { 13 | 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x48, 0x00, 0x88, 0x00, 0x08, 0x01, 0x08, 0x02, 0x08, 0x04, 14 | 0x08, 0x08, 0x08, 0x10, 0x08, 0x20, 0x08, 0x38, 0x88, 0x08, 0x48, 0x11, 0x28, 0x12, 0x18, 0x0c }; 15 | 16 | // 'icon_about', 16x16px 17 | const unsigned char bitmap_icon_about [] PROGMEM = { 18 | 0xc0, 0x03, 0x20, 0x04, 0x10, 0x08, 0x10, 0x08, 0x20, 0x04, 0xc0, 0x03, 0x00, 0x00, 0xf8, 0x1f, 19 | 0x04, 0x20, 0x02, 0x40, 0x02, 0x40, 0x12, 0x48, 0x12, 0x48, 0x12, 0x48, 0xfc, 0x3f, 0x00, 0x00 }; 20 | 21 | 22 | 23 | // 'scrollbar_background', 8x64px 24 | const unsigned char bitmap_scrollbar_background [] PROGMEM = { 25 | 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 26 | 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 27 | 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 28 | 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 29 | 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 30 | 0x00, 0x40, 0x00, 0x00, }; 31 | 32 | 33 | // 'item_sel_outline', 128x21px 34 | const unsigned char bitmap_item_sel_outline [] PROGMEM = { 35 | 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 36 | 0xFF, 0xFF, 0xFF, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 37 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 38 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 39 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 40 | 0x00, 0x00, 0x00, 0x0C, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 41 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x02, 0x00, 0x00, 0x00, 42 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 43 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 44 | 0x00, 0x00, 0x00, 0x0C, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x02, 0x00, 0x00, 0x00, 46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 47 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 48 | 0x00, 0x00, 0x00, 0x0C, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x02, 0x00, 0x00, 0x00, 50 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 51 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 52 | 0x00, 0x00, 0x00, 0x0C, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 53 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x02, 0x00, 0x00, 0x00, 54 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 55 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 56 | 0x00, 0x00, 0x00, 0x0C, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 57 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x02, 0x00, 0x00, 0x00, 58 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 59 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 60 | 0x00, 0x00, 0x00, 0x0C, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 61 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xF8, 0xFF, 0xFF, 0xFF, 62 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 63 | }; 64 | -------------------------------------------------------------------------------- /ColorReplica/colorpicker.cpp: -------------------------------------------------------------------------------- 1 | /* ____________________________ 2 | This software is licensed under the MIT License: 3 | https://github.com/cifertech/ColorReplica 4 | ________________________________________ */ 5 | 6 | #include 7 | #include "colorpicker.h" 8 | 9 | extern U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2; 10 | 11 | extern Adafruit_NeoPixel strip; 12 | 13 | #define PIN 23 14 | #define NUM_PIXELS 18 15 | #define DEFAULT_COLOR 0xFF0000 16 | #define DEFAULT_BRIGHTNESS 255 17 | 18 | const int touchPin1 = 12; 19 | const int touchPin2 = 13; 20 | const int touchPin3 = 14; 21 | const int touchPin4 = 15; 22 | 23 | const int threshold = 20; 24 | 25 | int touchValue1; 26 | int touchValue2; 27 | int touchValue3; 28 | int touchValue4; 29 | 30 | enum LightingMode { 31 | STATIC, 32 | TEST, 33 | CHASE 34 | }; 35 | 36 | uint32_t selectedColor = DEFAULT_COLOR; 37 | uint8_t selectedBrightness = DEFAULT_BRIGHTNESS; 38 | LightingMode selectedMode = STATIC; 39 | 40 | 41 | int br; 42 | void updateNeoPixelColorBrightness() { 43 | for (int i = 0; i < NUM_PIXELS; i++) { 44 | strip.setPixelColor(i, selectedColor); 45 | } 46 | strip.setBrightness(selectedBrightness); 47 | strip.show(); 48 | 49 | br = map(selectedBrightness, 0,255, 0,100); 50 | } 51 | 52 | 53 | void rainbow(int wait) { 54 | for (int i = 0; i < strip.numPixels(); i++) 55 | { 56 | strip.setPixelColor(i, 0, 0, 0); 57 | } 58 | strip.show(); 59 | int R = 0; int G = 0; int B = 0; 60 | int OldLamp; 61 | OldLamp = random(100,200); 62 | R = 250-OldLamp; G = R-255-OldLamp; B = 255-OldLamp; 63 | if(G<0) G=0; if(R<0) R=0; if(B<0) B=0; 64 | delay(random(100,150)); 65 | } 66 | 67 | 68 | void theaterChase(uint32_t color, int wait) { 69 | for (int a = 0; a < 10; a++) { 70 | for (int b = 0; b < 3; b++) { 71 | strip.clear(); 72 | for (int c = b; c < strip.numPixels(); c += 3) { 73 | strip.setPixelColor(c, color); 74 | } 75 | strip.show(); 76 | delay(wait); 77 | } 78 | } 79 | } 80 | 81 | String colorname; 82 | 83 | uint32_t colors[] = {0xf8f5f5, 0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF, 0x00FFFF}; 84 | String colorNames[] = {"White", "Red", "Green", "Blue", "Yellow", "Magenta", "Cyan"}; 85 | int currentColorIndex = 0; 86 | 87 | uint32_t getNextColor(uint32_t currentColor) { 88 | currentColorIndex = (currentColorIndex + 1) % (sizeof(colors) / sizeof(colors[0])); 89 | return colors[currentColorIndex]; 90 | } 91 | 92 | 93 | void updateOLED() { 94 | u8g2.clearBuffer(); 95 | u8g2.setFont(u8g_font_7x14B); 96 | u8g2.drawStr(0, 10, "Color:"); 97 | u8g2.drawStr(0, 30, "Brightness:"); 98 | u8g2.drawStr(0, 50, "Mode:"); 99 | u8g2.setCursor(80, 10); 100 | u8g2.print(colorNames[currentColorIndex]); 101 | u8g2.setCursor(80, 30); 102 | u8g2.print(br); 103 | u8g2.setCursor(80, 50); 104 | u8g2.print(selectedMode == STATIC ? "Static" : selectedMode == TEST ? "TEST" : "Chase"); 105 | u8g2.sendBuffer(); 106 | } 107 | 108 | 109 | void colorpickerSetup(){ 110 | 111 | strip.begin(); 112 | strip.show(); // Initialize all pixels to 'off' 113 | 114 | pinMode(17, INPUT_PULLUP); // Button to change color 115 | pinMode(16, INPUT_PULLUP); // Button to change brightness + 116 | pinMode(18, INPUT_PULLUP); // Button to change brightness - 117 | 118 | Serial.begin(9600); 119 | Serial.println("Serial NeoPixel Control"); 120 | Serial.println("Commands:"); 121 | Serial.println("CRRGGBB - Set color (RRGGBB is in hexadecimal)"); 122 | Serial.println("B### - Set brightness (0-255)"); 123 | Serial.println("M# - Set mode (0: Static, 1: TEST, 2: Chase)"); 124 | Serial.println("Example: C00FF00 - Set color to green"); 125 | Serial.println("Example: B128 - Set brightness to 128"); 126 | Serial.println("Example: M1 - Set mode to TEST"); 127 | Serial.println(); 128 | Serial.print("Current Color: #"); 129 | Serial.println(selectedColor, HEX); 130 | Serial.print("Current Brightness: "); 131 | Serial.println(selectedBrightness); 132 | Serial.print("Current Mode: "); 133 | Serial.println(selectedMode == STATIC ? "Static" : selectedMode == TEST ? "TEST" : "Chase"); 134 | 135 | u8g2.begin(); 136 | u8g2.clearBuffer(); 137 | u8g2.setFont(u8g_font_7x14B); 138 | u8g2.drawStr(0, 10, "Color:"); 139 | u8g2.drawStr(0, 30, "Brightness:"); 140 | u8g2.drawStr(0, 50, "Mode:"); 141 | u8g2.sendBuffer(); 142 | } 143 | 144 | 145 | void colorpickerLoop(){ 146 | 147 | touchValue1 = touchRead(touchPin1); 148 | touchValue2 = touchRead(touchPin2); 149 | touchValue3 = touchRead(touchPin3); 150 | touchValue4 = touchRead(touchPin4); 151 | 152 | if (touchValue1 < threshold) { 153 | selectedColor = getNextColor(selectedColor); 154 | updateNeoPixelColorBrightness(); 155 | Serial.print("New Color: #"); 156 | Serial.println(selectedColor, HEX); 157 | updateOLED(); 158 | delay(500); 159 | } 160 | 161 | 162 | if (touchValue3 < threshold) { 163 | if (selectedBrightness > 0) { 164 | selectedBrightness = selectedBrightness - 50; 165 | updateNeoPixelColorBrightness(); 166 | Serial.print("New Brightness: "); 167 | Serial.println(selectedBrightness); 168 | updateOLED(); 169 | } 170 | delay(500); 171 | } 172 | 173 | 174 | if (touchValue2 < threshold) { 175 | selectedMode = static_cast((selectedMode + 1) % 3); 176 | Serial.print("New Mode: "); 177 | Serial.println(selectedMode == STATIC ? "Static" : selectedMode == CHASE ? "TEST" : "Chase"); 178 | updateNeoPixelColorBrightness(); 179 | updateOLED(); 180 | delay(500); 181 | } 182 | 183 | if (Serial.available() > 0) { 184 | char command = Serial.read(); 185 | if (command == 'C') { 186 | // Set color based on hexadecimal input (e.g., C00FF00 for green) 187 | selectedColor = strtol(Serial.readStringUntil('\n').c_str(), NULL, 16); 188 | updateNeoPixelColorBrightness(); 189 | Serial.print("New Color: #"); 190 | Serial.println(selectedColor, HEX); 191 | updateOLED(); 192 | } else if (command == 'B') { 193 | // Set brightness (0-255) 194 | selectedBrightness = Serial.parseInt(); 195 | updateNeoPixelColorBrightness(); 196 | Serial.print("New Brightness: "); 197 | Serial.println(selectedBrightness); 198 | updateOLED(); 199 | } else if (command == 'M') { 200 | // Set lighting mode (0: Static, 1: TEST, 2: Chase) 201 | selectedMode = static_cast(Serial.parseInt()); 202 | Serial.print("New Mode: "); 203 | Serial.println(selectedMode == STATIC ? "Static" : selectedMode == TEST ? "TEST" : "Chase"); 204 | } 205 | } 206 | 207 | 208 | switch (selectedMode) { 209 | case STATIC: 210 | 211 | break; 212 | case TEST: 213 | 214 | rainbow(20); 215 | break; 216 | case CHASE: 217 | 218 | theaterChase(selectedColor, 50); 219 | break; 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /ColorReplica/ColorReplica.ino: -------------------------------------------------------------------------------- 1 | /* ____________________________ 2 | This software is licensed under the MIT License: 3 | https://github.com/cifertech/ColorReplica 4 | ________________________________________ */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #ifdef U8X8_HAVE_HW_I2C 11 | #include 12 | #endif 13 | 14 | #include "icon.h" 15 | #include "colorpicker.h" 16 | #include "reciver.h" 17 | 18 | #define PIN 23 19 | #define NUM_PIXELS 18 20 | 21 | //U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0); // [full framebuffer, size = 1024 bytes] 22 | U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); 23 | 24 | Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_PIXELS, PIN, NEO_GRB + NEO_KHZ800); 25 | 26 | 27 | const unsigned char* bitmap_icons[8] = { 28 | bitmap_icon_colorcube, 29 | bitmap_icon_colorpicker, 30 | bitmap_icon_about 31 | }; 32 | 33 | 34 | const int NUM_ITEMS = 3; 35 | const int MAX_ITEM_LENGTH = 20; 36 | 37 | char menu_items [NUM_ITEMS] [MAX_ITEM_LENGTH] = { 38 | { "Color Cube" }, 39 | { "Color Picker" }, 40 | { "About" } 41 | }; 42 | 43 | 44 | #define BUTTON_UP_PIN 18 45 | #define BUTTON_SELECT_PIN 16 46 | #define BUTTON_DOWN_PIN 17 47 | 48 | 49 | int button_up_clicked = 0; 50 | int button_select_clicked = 0; 51 | int button_down_clicked = 0; 52 | 53 | int item_selected = 0; 54 | 55 | int item_sel_previous; 56 | int item_sel_next; 57 | 58 | int current_screen = 0; 59 | 60 | 61 | void about() { 62 | u8g2.clearBuffer(); 63 | u8g2.setFont(u8g2_font_6x10_tf); 64 | u8g2.drawStr(7, 15, "CiferTech@gmail.com"); 65 | u8g2.drawStr(12, 35, "GitHub/cifertech"); 66 | u8g2.drawStr(7, 55, "instagram/cifertech"); 67 | u8g2.sendBuffer(); 68 | } 69 | 70 | 71 | void setup() { 72 | 73 | u8g2.begin(); 74 | u8g2.setBitmapMode(1); 75 | 76 | pinMode(BUTTON_UP_PIN, INPUT_PULLUP); 77 | pinMode(BUTTON_SELECT_PIN, INPUT_PULLUP); 78 | pinMode(BUTTON_DOWN_PIN, INPUT_PULLUP); 79 | 80 | } 81 | 82 | 83 | void loop() { 84 | 85 | if (current_screen == 0) { // MENU SCREEN 86 | 87 | for (int i = 0; i < strip.numPixels(); i++){ 88 | strip.setPixelColor(i, 0, 0, 0); 89 | } 90 | strip.show(); 91 | 92 | 93 | if ((digitalRead(BUTTON_UP_PIN) == LOW) && (button_up_clicked == 0)) { 94 | item_selected = item_selected - 1; 95 | button_up_clicked = 1; 96 | if (item_selected < 0) { 97 | item_selected = NUM_ITEMS-1; 98 | } 99 | } 100 | else if ((digitalRead(BUTTON_DOWN_PIN) == LOW) && (button_down_clicked == 0)) { 101 | item_selected = item_selected + 1; 102 | button_down_clicked = 1; 103 | if (item_selected >= NUM_ITEMS) { 104 | item_selected = 0; 105 | } 106 | } 107 | 108 | if ((digitalRead(BUTTON_UP_PIN) == HIGH) && (button_up_clicked == 1)) { 109 | button_up_clicked = 0; 110 | } 111 | if ((digitalRead(BUTTON_DOWN_PIN) == HIGH) && (button_down_clicked == 1)) { 112 | button_down_clicked = 0; 113 | } 114 | } 115 | 116 | 117 | bool callAbout = true; 118 | 119 | if ((digitalRead(BUTTON_SELECT_PIN) == LOW) && (button_select_clicked == 0)) { 120 | button_select_clicked = 1; 121 | 122 | if (current_screen == 0 && item_selected == 1) { 123 | colorpickerSetup(); 124 | while (item_selected == 1) { 125 | if (digitalRead(BUTTON_SELECT_PIN) == HIGH) { 126 | colorpickerLoop(); 127 | if (callAbout) { 128 | callAbout = false; // Toggle the state to not call about() 129 | } else { 130 | break; // Toggle the state to break the loop 131 | callAbout = true; // Reset the state for the next cycle 132 | } 133 | 134 | while (digitalRead(BUTTON_SELECT_PIN) == HIGH) { 135 | // Wait for the button to be released 136 | 137 | if (callAbout = true){ 138 | break; 139 | } 140 | } 141 | } 142 | } 143 | } 144 | 145 | 146 | if (current_screen == 0 && item_selected == 0) { 147 | reciverSetup(); 148 | while (item_selected == 0) { 149 | if (digitalRead(BUTTON_SELECT_PIN) == HIGH) { 150 | if (callAbout) { 151 | reciverLoop(); 152 | callAbout = false; // Toggle the state to not call about() 153 | } else { 154 | break; // Toggle the state to break the loop 155 | callAbout = true; // Reset the state for the next cycle 156 | } 157 | 158 | while (digitalRead(BUTTON_SELECT_PIN) == HIGH) { 159 | // Wait for the button to be released 160 | if (callAbout = true){ 161 | break; 162 | } 163 | } 164 | } 165 | } 166 | } 167 | 168 | 169 | 170 | if (current_screen == 0 && item_selected == 2) { 171 | while (item_selected == 2) { 172 | if (digitalRead(BUTTON_SELECT_PIN) == HIGH) { 173 | if (callAbout) { 174 | about(); 175 | callAbout = false; // Toggle the state to not call about() 176 | } else { 177 | break; // Toggle the state to break the loop 178 | callAbout = true; // Reset the state for the next cycle 179 | } 180 | 181 | while (digitalRead(BUTTON_SELECT_PIN) == HIGH) { 182 | // Wait for the button to be released 183 | if (callAbout = true){ 184 | break; 185 | } 186 | } 187 | } 188 | } 189 | } 190 | } 191 | 192 | if ((digitalRead(BUTTON_SELECT_PIN) == HIGH) && (button_select_clicked == 1)) { 193 | button_select_clicked = 0; 194 | } 195 | 196 | 197 | item_sel_previous = item_selected - 1; 198 | if (item_sel_previous < 0) {item_sel_previous = NUM_ITEMS - 1;} 199 | item_sel_next = item_selected + 1; 200 | if (item_sel_next >= NUM_ITEMS) {item_sel_next = 0;} 201 | 202 | 203 | 204 | u8g2.clearBuffer(); 205 | 206 | if (current_screen == 0) { 207 | 208 | u8g2.drawXBMP(0, 22, 128, 21, bitmap_item_sel_outline); 209 | 210 | u8g2.setFont(u8g_font_7x14); 211 | u8g2.drawStr(25, 15, menu_items[item_sel_previous]); 212 | u8g2.drawXBMP( 4, 2, 16, 16, bitmap_icons[item_sel_previous]); 213 | 214 | u8g2.setFont(u8g_font_7x14B); 215 | u8g2.drawStr(25, 15+20+2, menu_items[item_selected]); 216 | u8g2.drawXBMP( 4, 24, 16, 16, bitmap_icons[item_selected]); 217 | 218 | u8g2.setFont(u8g_font_7x14); 219 | u8g2.drawStr(25, 15+20+20+2+2, menu_items[item_sel_next]); 220 | u8g2.drawXBMP( 4, 46, 16, 16, bitmap_icons[item_sel_next]); 221 | 222 | u8g2.drawXBMP(128-8, 0, 8, 64, bitmap_scrollbar_background); 223 | 224 | u8g2.drawBox(125, 64/NUM_ITEMS * item_selected, 3, 64/NUM_ITEMS); 225 | } 226 | 227 | u8g2.sendBuffer(); 228 | 229 | } 230 | --------------------------------------------------------------------------------