# Smart Light Control

This project focuses on creating an interactive lighting system using the [ACROME SMD](https://docs.acrome.net/electronics/smd-red) platform, incorporating an [Ambient Light Sensor](https://docs.acrome.net/electronics/add-on-modules/ambient-light-sensor-module), an [RGB LED Module](https://docs.acrome.net/electronics/add-on-modules/rgb-led-module), and a [Button Module](https://docs.acrome.net/electronics/add-on-modules/button-module). The system allows for automatic lighting control based on ambient light conditions and provides user interactivity to change the LED color. Additionally, the [Button Module](https://docs.acrome.net/electronics/add-on-modules/button-module) allows the user to cycle through colors, and when held down, it will quickly transition between colors. The LED will retain the last selected color after the button is released.

**About Tools and Materials:**

[SMD Red](https://docs.acrome.net/electronics/smd-red) ([Purchase Here](https://www.robotshop.com/products/acrome-smd-red-smart-brushed-motor-driver-with-speed-position-and-current-control-modes))

[SMD USB Gateway](https://docs.acrome.net/electronics/gateway-modules/usb-gateway-module) ([Purchase Here](https://www.robotshop.com/products/acrome-usb-gateway-module-acrome-smd-products))

[Arduino Gateway Module](https://docs.acrome.net/electronics/gateway-modules/arduino-gateway-module) ([Purchase Here](https://www.robotshop.com/products/acrome-arduino-gateway-shield-module-acrome-smd-products))

[RGB LED Module](https://docs.acrome.net/electronics/add-on-modules/rgb-led-module) ([Purchase Here](https://www.robotshop.com/products/acrome-rgb-led-add-on-module-acrome-smd-products))

[Button Module](https://docs.acrome.net/electronics/add-on-modules/button-module) ([Purchase Here](https://www.robotshop.com/products/acrome-button-add-on-module-acrome-smd-products?pr_prod_strat=e5_desc\&pr_rec_id=e23ece12f\&pr_rec_pid=8120246796449\&pr_ref_pid=8121226592417\&pr_seq=uniform))

[Ambient Light Sensor Module](https://docs.acrome.net/electronics/add-on-modules/ambient-light-sensor-module) ([Purchase Here](https://www.robotshop.com/products/acrome-ambient-light-sensor-add-on-module-acrome-smd-products))

## **Step 1: Hardware & Software Overview** <a href="#step-1-hardware-and-software-overview" id="step-1-hardware-and-software-overview"></a>

**Key Components:**

1. [SMD](https://docs.acrome.net/electronics/smd-red)\
   The [SMD](https://docs.acrome.net/electronics/smd-red) serves as the central communication hub between the different modules. It manages the interaction between the [Ambient Light Sensor](https://docs.acrome.net/electronics/add-on-modules/ambient-light-sensor-module), [RGB LED Module](https://docs.acrome.net/electronics/add-on-modules/rgb-led-module), and [Button Module](https://docs.acrome.net/electronics/add-on-modules/button-module), executing the logic as defined in the script.
2. [RGB LED Module ](https://docs.acrome.net/electronics/add-on-modules/rgb-led-module)\
   The [RGB LED Module](https://docs.acrome.net/electronics/add-on-modules/rgb-led-module) emits light in different colors by mixing red, green, and blue channels. This allows users to create a variety of lighting effects, controlled via the [Button Module](https://docs.acrome.net/electronics/add-on-modules/button-module).
3. [Button Module ](https://docs.acrome.net/electronics/add-on-modules/button-module)\
   The [Button Module ](https://docs.acrome.net/electronics/add-on-modules/button-module)serves as a physical interface for user input. Users can press the button to cycle through different colors for the [RGB LED Module](https://docs.acrome.net/electronics/add-on-modules/rgb-led-module), and if the button is held down, the system will rapidly cycle through colors, allowing for faster color selection.
4. [Ambient Light Sensor Module ](https://docs.acrome.net/electronics/add-on-modules/ambient-light-sensor-module)\
   The [Ambient Light Sensor](https://docs.acrome.net/electronics/add-on-modules/ambient-light-sensor-module) detects the intensity of the surrounding light and allows the system to decide when to automatically turn on or off the [RGB LED Module](https://docs.acrome.net/electronics/add-on-modules/rgb-led-module), depending on the environment’s lighting conditions.

**Project Key Features:**

1. Automatic Light Sensing \
   The [Ambient Light Sensor Module ](https://docs.acrome.net/electronics/add-on-modules/ambient-light-sensor-module)continuously monitors the environmental light levels. When the light intensity falls below a predefined threshold, the system automatically activates the [RGB LED Module](https://docs.acrome.net/electronics/add-on-modules/rgb-led-module). This ensures that the light is only turned on when needed, enhancing energy efficiency and creating an adaptive lighting environment.
2. Manual Color Control \
   The user can interact with the [Button Module](https://docs.acrome.net/electronics/add-on-modules/button-module) to manually change the color of the [RGB LED Module](https://docs.acrome.net/electronics/add-on-modules/rgb-led-module). Each button press cycles through a preset list of colors (e.g., red, green, blue, yellow, magenta, cyan). Additionally, holding the button down accelerates the color transitions, allowing users to quickly move between colors.
3. Energy-Efficient Operation \
   The [Ambient Light Sensor Module](https://docs.acrome.net/electronics/add-on-modules/ambient-light-sensor-module) makes the system more energy-efficient by turning the light off when ambient light levels are sufficient. This feature ensures that the [RGB LED Module](https://docs.acrome.net/electronics/add-on-modules/rgb-led-module) operates only in low-light conditions, minimizing unnecessary energy usage.
4. Seamless Module Communication \
   The [SMD](https://docs.acrome.net/electronics/smd-red) ensures seamless communication between all components. It reads the ambient light data from the [Ambient Light Sensor](https://docs.acrome.net/electronics/add-on-modules/ambient-light-sensor-module), controls the color output of the [RGB LED](https://docs.acrome.net/electronics/add-on-modules/rgb-led-module), and processes user input from the [Button Module](https://docs.acrome.net/electronics/add-on-modules/button-module). This integration allows the project to react dynamically to both environmental changes and user commands.

## **Step 2: Assemble**

**Getting Started**

1. **Hardware Setup**
   * Connect the SMD to the PC or Arduino board using [USB Gateway Module](https://docs.acrome.net/electronics/gateway-modules/usb-gateway-module) or [Arduino Gateway Module](https://docs.acrome.net/electronics/gateway-modules/arduino-gateway-module).
   * Connect the [Ambient Light Sensor Module](https://docs.acrome.net/electronics/add-on-modules/ambient-light-sensor-module) and the [RGB LED Module](https://docs.acrome.net/electronics/add-on-modules/rgb-led-module) to the SMD using an RJ-45 cable.
   * Make sure that the SMD is powered and all connections are correct.

#### Project Wiring Diagram

<figure><img src="https://1077748559-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LuxEcL3mxZNc5Aa92N6%2Fuploads%2F6NU5Tnv3kOvi6uMLelk0%2FSmart%20Light%20Control.png?alt=media&#x26;token=37c957a4-27b8-434d-b891-daf0a21f2966" alt=""><figcaption></figcaption></figure>

## Step 3: Run & Test

* Light Monitoring: The system constantly reads ambient light data using the [Ambient Light Sensor](https://docs.acrome.net/electronics/add-on-modules/ambient-light-sensor-module).
* Automatic Light Control: If the environment is too dark, the [RGB LED Module](https://docs.acrome.net/electronics/add-on-modules/rgb-led-module) is automatically turned on, and if the environment is bright, the [RGB LED Module](https://docs.acrome.net/electronics/add-on-modules/rgb-led-module) turns off.
* User Interaction: The [Button Module](https://docs.acrome.net/electronics/add-on-modules/button-module) allows the user to cycle through colors manually. A single press changes the color, and holding the button down rapidly switches between the colors.
* Color Retention: When the button is released, the LED remains on the last selected color until further interaction.

## **Codes**

{% tabs %}
{% tab title="Python Code" %}
{% code lineNumbers="true" %}

```python
from smd.red import *
import time
import tkinter as tk
from tkinter import messagebox
from threading import Thread
import json
import os
from serial.tools.list_ports import comports
from platform import system


# Serial Communication Settings
baudrate = 115200          # Baud rate of communication
ID = 0                     # ID of the SMD module
button_module_id = 5       # ID of the button module
light_sensor_id = 5        # ID of the light sensor module
rgb_led_id = 5             # ID of the RGB LED module


def USB_Port():
    """
    Scans and identifies a compatible USB port for the current operating system.

    Returns:
        str: The detected USB port or None if no suitable port is found.
    """
    ports = list(comports())

    usb_names = {
        "Windows": ["USB Serial Port"],
        "Linux": ["/dev/ttyUSB"],
        "Darwin": [
            "/dev/tty.usbserial",
            "/dev/tty.usbmodem",
            "/dev/tty.SLAB_USBtoUART",
            "/dev/tty.wchusbserial",
            "/dev/cu.usbserial",
            "/dev/cu.usbmodem",
            "/dev/cu.SLAB_USBtoUART",
            "/dev/cu.wchusbserial",
        ]
    }

    # Detect the operating system
    os_name = system()
    print(f"Operating System: {os_name}")

    if ports:
        for port in ports:
            if any(name in port.device or name in port.description for name in usb_names.get(os_name, [])):
                print(f"USB device detected on port: {port.device}")
                return port.device
        print("No suitable USB device found. Available ports:")
        for port in ports:
            print(f"Port: {port.device}, Description: {port.description}, HWID: {port.hwid}")
    else:
        print("No ports detected!")
    return None


# Initialize the USB port and SMD module
SerialPort = USB_Port()
if not SerialPort:
    raise Exception("No compatible USB port found. Please check your connection.")

master = Master(SerialPort, baudrate)
master.attach(Red(ID))
print("Connected Modules:", master.scan_modules(ID))


# Color Management Functions
def load_colors_from_json():
    """
    Load colors from a JSON file. If the file doesn't exist, return an empty list.

    Returns:
        list: A list of RGB color tuples, or an empty list if the file is not found.
    """
    if os.path.exists("rgbsetting.json"):
        with open("rgbsetting.json", "r") as f:
            data = json.load(f)
            return data.get("colors", [])
    return []


def save_color_to_json():
    """
    Save the current list of colors to a JSON file.
    """
    data = {"colors": colors}
    with open("rgbsetting.json", "w") as f:
        json.dump(data, f, indent=4)
    print("Colors saved to rgbsetting.json")


# Default Colors
default_colors = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0), (255, 0, 255), (0, 255, 255)]
colors = load_colors_from_json() or default_colors
color_index = 0  # Tracks the current color index


# GUI Setup
window = tk.Tk()
window.title("LED Color Controller")
window.geometry("400x300")


# GUI Widgets
light_label = tk.Label(window, text="Light Status: ", font=("Helvetica", 14))
light_label.pack(pady=10)

button_label = tk.Label(window, text="Button State: ", font=("Helvetica", 14))
button_label.pack(pady=10)

color_label = tk.Label(window, text="Current Color: ", font=("Helvetica", 14))
color_label.pack(pady=10)

r_label = tk.Label(window, text="R:", font=("Helvetica", 12))
r_label.pack(side=tk.LEFT, padx=(10, 0))
r_entry = tk.Entry(window, width=5)
r_entry.pack(side=tk.LEFT)

g_label = tk.Label(window, text="G:", font=("Helvetica", 12))
g_label.pack(side=tk.LEFT, padx=(10, 0))
g_entry = tk.Entry(window, width=5)
g_entry.pack(side=tk.LEFT)

b_label = tk.Label(window, text="B:", font=("Helvetica", 12))
b_label.pack(side=tk.LEFT, padx=(10, 0))
b_entry = tk.Entry(window, width=5)
b_entry.pack(side=tk.LEFT)

save_var = tk.BooleanVar()
save_checkbox = tk.Checkbutton(window, text="Save color to file", variable=save_var)
save_checkbox.pack(pady=5)

add_button = tk.Button(window, text="Add Color", command=lambda: add_color())
add_button.pack(pady=10)


# Helper Functions
def validate_rgb_value(value):
    """
    Validates whether the given value is an integer between 0 and 255.

    Args:
        value (str): RGB value as string.
    Returns:
        bool: True if valid, False otherwise.
    """
    try:
        value = int(value)
        return 0 <= value <= 255
    except ValueError:
        return False


def add_color():
    """
    Adds a new color to the colors list and saves it to a JSON file if required.
    """
    r, g, b = r_entry.get(), g_entry.get(), b_entry.get()
    if validate_rgb_value(r) and validate_rgb_value(g) and validate_rgb_value(b):
        r, g, b = int(r), int(g), int(b)
        colors.append((r, g, b))
        print(f"New color added: R={r}, G={g}, B={b}")
        if save_var.get():
            save_color_to_json()
    else:
        messagebox.showerror("Invalid Input", "RGB values must be integers between 0 and 255.")


def update_gui(light_status, button_status, current_color):
    """
    Updates the GUI labels and background color based on the current state.

    Args:
        light_status (str): Current status of the light (On/Off).
        button_status (str): Current state of the button (Pressed/Released).
        current_color (tuple): RGB values of the current LED color.
    """
    light_label.config(text=f"Light Status: {light_status}")
    button_label.config(text=f"Button State: {button_status}")
    color_label.config(text=f"Current Color: R={current_color[0]}, G={current_color[1]}, B={current_color[2]}")
    window.configure(bg=f'#{current_color[0]:02x}{current_color[1]:02x}{current_color[2]:02x}')


# Main Control Loop
def control_loop():
    """
    Main control loop for managing the RGB LED light and updating GUI elements.
    """
    global color_index
    button_held = False

    while True:
        light = master.get_light(ID, light_sensor_id)
        button_pressed = master.get_button(ID, button_module_id)

        # Determine light status based on sensor reading
        if light is not None and light < 100:
            light_status = "On"
        else:
            light_status = "Off"

        # Handle button press to change colors
        if button_pressed == 1 and not button_held:
            button_held = True
            color_index = (color_index + 1) % len(colors)
            r, g, b = colors[color_index]
            master.set_rgb(ID, rgb_led_id, r, g, b)
        elif button_pressed == 0:
            button_held = False

        # Update GUI with the current state
        r, g, b = colors[color_index] if light_status == "On" else (0, 0, 0)
        update_gui(light_status, "Pressed" if button_pressed else "Released", (r, g, b))
        time.sleep(0.1)


# Start control loop in a separate thread
control_thread = Thread(target=control_loop)
control_thread.daemon = True
control_thread.start()

# Run the GUI main loop
window.mainloop()
```

{% endcode %}
{% endtab %}

{% tab title="Arduino Code" %}
{% code lineNumbers="true" %}

```cpp
#include <Acrome-SMD.h>

#define ID        0           // ID of the SMD module
#define BAUDRATE  115200      // Baud rate for communication

Red master(ID, Serial, BAUDRATE);    // Defines the Arduino gateway module

const int rgb_module_id = 5;         // ID of the RGB LED module
const int button_module_id = 5;      // ID of the button module (assuming it's the same as the RGB module)
const int light_sensor_module_id = 5; // ID of the light sensor module (assuming it's the same as the RGB module)

// RGB color array
const int COLOR_COUNT = 6;
int colors[][3] = {
  {255, 0, 0},    // Red
  {0, 255, 0},    // Green
  {0, 0, 255},    // Blue
  {255, 255, 0},  // Yellow
  {255, 0, 255},  // Magenta
  {0, 255, 255}   // Cyan
};

int colorIndex = 0;
bool currentButtonState = false;

void setup() {
    master.begin();                 // Initialize communication
    master.scanModules();           // Scan for connected modules
    Serial.begin(BAUDRATE);
}

void loop() {
    // Read ambient light level
    int lightLevel = master.getLight(light_sensor_module_id);
    Serial.println(lightLevel);
    
    // Determine whether the light should be on or off
    bool shouldLightBeOn = (lightLevel > 100);

    // Read button state
    bool currentButtonState = master.getButton(button_module_id);

    // Change color when the button is pressed
    if (currentButtonState) {
        colorIndex = (colorIndex + 1) % COLOR_COUNT;
    }

    // Update RGB LED based on light level
    if (shouldLightBeOn) {
        master.setRGB(rgb_module_id, colors[colorIndex][0], colors[colorIndex][1], colors[colorIndex][2]);
    } else {
        master.setRGB(rgb_module_id, 0, 0, 0);  // Turn off the LED
    }

    delay(100);  // Short delay to control the loop speed
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

**Conclusion:**

This project exemplifies how the [ACROME SMD](https://docs.acrome.net/electronics/smd-red) platform can integrate with various modules to create a smart lighting solution that is both interactive and energy-efficient. By using the [Ambient Light Sensor](https://docs.acrome.net/electronics/add-on-modules/ambient-light-sensor-module), [RGB LED](https://docs.acrome.net/electronics/add-on-modules/rgb-led-module), and [Button Module](https://docs.acrome.net/electronics/add-on-modules/button-module), the system combines automatic control with manual user inputs, providing a flexible and customizable lighting experience.
