# Smart Light Control

This project focuses on creating an interactive lighting system using the [ACROME SMD](/electronics/smd-red.md) platform, incorporating an [Ambient Light Sensor](/electronics/add-on-modules/ambient-light-sensor-module.md), an [RGB LED Module](/electronics/add-on-modules/rgb-led-module.md), and a [Button Module](/electronics/add-on-modules/button-module.md). 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](/electronics/add-on-modules/button-module.md) 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](/electronics/gateway-modules/arduino-gateway-module.md) ([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](/electronics/add-on-modules/button-module.md) ([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](/electronics/smd-red.md)\
   The [SMD](/electronics/smd-red.md) serves as the central communication hub between the different modules. It manages the interaction between the [Ambient Light Sensor](/electronics/add-on-modules/ambient-light-sensor-module.md), [RGB LED Module](/electronics/add-on-modules/rgb-led-module.md), and [Button Module](/electronics/add-on-modules/button-module.md), executing the logic as defined in the script.
2. [RGB LED Module ](/electronics/add-on-modules/rgb-led-module.md)\
   The [RGB LED Module](/electronics/add-on-modules/rgb-led-module.md) 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](/electronics/add-on-modules/button-module.md).
3. [Button Module ](/electronics/add-on-modules/button-module.md)\
   The [Button Module ](/electronics/add-on-modules/button-module.md)serves as a physical interface for user input. Users can press the button to cycle through different colors for the [RGB LED Module](/electronics/add-on-modules/rgb-led-module.md), and if the button is held down, the system will rapidly cycle through colors, allowing for faster color selection.
4. [Ambient Light Sensor Module ](/electronics/add-on-modules/ambient-light-sensor-module.md)\
   The [Ambient Light Sensor](/electronics/add-on-modules/ambient-light-sensor-module.md) detects the intensity of the surrounding light and allows the system to decide when to automatically turn on or off the [RGB LED Module](/electronics/add-on-modules/rgb-led-module.md), depending on the environment’s lighting conditions.

**Project Key Features:**

1. Automatic Light Sensing \
   The [Ambient Light Sensor Module ](/electronics/add-on-modules/ambient-light-sensor-module.md)continuously monitors the environmental light levels. When the light intensity falls below a predefined threshold, the system automatically activates the [RGB LED Module](/electronics/add-on-modules/rgb-led-module.md). 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](/electronics/add-on-modules/button-module.md) to manually change the color of the [RGB LED Module](/electronics/add-on-modules/rgb-led-module.md). 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](/electronics/add-on-modules/ambient-light-sensor-module.md) 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](/electronics/add-on-modules/rgb-led-module.md) operates only in low-light conditions, minimizing unnecessary energy usage.
4. Seamless Module Communication \
   The [SMD](/electronics/smd-red.md) ensures seamless communication between all components. It reads the ambient light data from the [Ambient Light Sensor](/electronics/add-on-modules/ambient-light-sensor-module.md), controls the color output of the [RGB LED](/electronics/add-on-modules/rgb-led-module.md), and processes user input from the [Button Module](/electronics/add-on-modules/button-module.md). 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="/files/grFZD8x6asti9phIOB8g" alt=""><figcaption></figcaption></figure>

## Step 3: Run & Test

* Light Monitoring: The system constantly reads ambient light data using the [Ambient Light Sensor](/electronics/add-on-modules/ambient-light-sensor-module.md).
* Automatic Light Control: If the environment is too dark, the [RGB LED Module](/electronics/add-on-modules/rgb-led-module.md) is automatically turned on, and if the environment is bright, the [RGB LED Module](/electronics/add-on-modules/rgb-led-module.md) turns off.
* User Interaction: The [Button Module](/electronics/add-on-modules/button-module.md) 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](/electronics/smd-red.md) 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](/electronics/add-on-modules/ambient-light-sensor-module.md), [RGB LED](/electronics/add-on-modules/rgb-led-module.md), and [Button Module](/electronics/add-on-modules/button-module.md), the system combines automatic control with manual user inputs, providing a flexible and customizable lighting experience.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.acrome.net/smd-applications/basics/smart-light-control.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
