๐Ÿ”ฆ Level 2 โ€“ Sensors & IR Control

Project 2.10: "Intelligent Environment Control"

๐Ÿš€ Project 2.10 โ€“ Intelligent Environment Control

ย 

๐ŸŽฏ What Youโ€™ll Learn

  • โœ… Goal 1: Automatically control ambient lighting with a photoresistor (light sensor).
  • โœ… Goal 2: Change RGB colors based on light intensity.
  • โœ… Goal 3: Switch between automatic day/night modes.
  • โœ… Goal 4: Create smooth color transitions.
  • โœ… Goal 5: Add custom configuration (thresholds and brightness limits).

Key Ideas

  • Short definition: A photoresistor changes its reading with light, letting your robot adapt its lights.
  • Realโ€‘world link: Smart bulbs and garden lights autoโ€‘adjust brightness at dusk and dawn.

๐Ÿงฑ Blocks Glossary

  • Analog input (photoresistor):
    • adc32 = machine.ADC(machine.Pin(32)) โ†’ Create ADC on pin 32.
    • adc32.atten(machine.ADC.ATTN_11DB) โ†’ Set attenuation for wider voltage range.
    • adc32.width(machine.ADC.WIDTH_12BIT) โ†’ 12โ€‘bit resolution (0โ€“4095).
    • adc32.read() โ†’ Read light value.
  • RGB outputs (PWM):
    • pwm2 = machine.PWM(machine.Pin(2)) โ†’ Red channel.
    • pwm4 = machine.PWM(machine.Pin(4)) โ†’ Green channel.
    • pwm5 = machine.PWM(machine.Pin(5)) โ†’ Blue channel.
    • pwmX.duty(value) โ†’ Brightness (0โ€“1023 typical).
    • pwmX.freq(2000) โ†’ Optional PWM frequency set.
  • Control:
    • while True: โ†’ Continuous loop.
    • for i in range(start, stop, step): โ†’ Smooth stepping.
    • if / elif / else: โ†’ Mode logic.
  • Serial:
    • print("...") โ†’ Feedback messages.

๐Ÿงฐ What You Need

PartHow many?Pin connection
D1 R321USB
Photoresistor module1ADC pin 32
RGB LED (common)1Red=2, Green=4, Blue=5

๐Ÿ”Œ Wiring tip: Connect photoresistor module output to pin 32 (ADC). Use pins 2/4/5 for RGB PWM outputs. Ensure common ground between sensor and board.


โœ… Before You Start

print("Ready!")  # Print startup message to confirm serial monitor works

๐ŸŽฎ Microprojects (1โ€“5)


๐ŸŽฎ Microproject 2.10.1 โ€“ Automatic ambient lighting

Goal: Dim or brighten a light based on sensor reading.

# Automatic ambient lighting                                 # Title: auto brightness by light sensor

import machine, time                                         # Import machine for ADC/PWM and time for delays

adc32 = machine.ADC(machine.Pin(32))                         # Create ADC on pin 32 for photoresistor
adc32.atten(machine.ADC.ATTN_11DB)                           # Set 11dB attenuation for wider input range
adc32.width(machine.ADC.WIDTH_12BIT)                         # Use 12-bit resolution (0โ€“4095 values)

pwm2 = machine.PWM(machine.Pin(2))                           # Setup PWM on pin 2 for Red LED channel
pwm2.freq(2000)                                              # Optional: set PWM frequency to 2000 Hz

print("Ambient lighting ready")                              # Serial confirmation

while True:                                                  # Continuous loop
    light = adc32.read()                                     # Read current light intensity from sensor
    duty = min(1023, max(0, 1023 - light // 4))              # Map light to duty (brighter when darker)
    pwm2.duty(duty)                                          # Apply computed duty to Red LED
    print("Light:", light, "Duty:", duty)                    # Print readings and output for debugging
    time.sleep(0.2)                                          # Small delay for stability
  • Reflection: The LED brightens in darkness and dims in bright light.
  • Challenge: Invert the behavior so it gets brighter when light increases.

๐ŸŽฎ Microproject 2.10.2 โ€“ Color change due to light intensity

Goal: Use light ranges to select colors (Blue in dark, Green medium, Red bright).

# Color change due to light intensity                         # Title: choose colors by light ranges

import machine, time                                         # Import libraries

adc32 = machine.ADC(machine.Pin(32))                         # ADC on pin 32 for photoresistor
adc32.atten(machine.ADC.ATTN_11DB)                           # Set attenuation for full-scale input
adc32.width(machine.ADC.WIDTH_12BIT)                         # 12-bit resolution for precise readings

pwm2 = machine.PWM(machine.Pin(2))                           # Red channel PWM on pin 2
pwm4 = machine.PWM(machine.Pin(4))                           # Green channel PWM on pin 4
pwm5 = machine.PWM(machine.Pin(5))                           # Blue channel PWM on pin 5

pwm2.freq(2000)                                              # Optional frequency set for Red
pwm4.freq(2000)                                              # Optional frequency set for Green
pwm5.freq(2000)                                              # Optional frequency set for Blue

print("Color change by light ready")                         # Serial confirmation

while True:                                                  # Loop forever
    light = adc32.read()                                     # Read light intensity
    print("Light:", light)                                   # Show raw light value

    if light < 1200:                                         # Dark range
        pwm2.duty(0)                                         # Red OFF
        pwm4.duty(0)                                         # Green OFF
        pwm5.duty(800)                                       # Blue ON (cool in dark)
    elif light < 2800:                                       # Medium range
        pwm2.duty(0)                                         # Red OFF
        pwm4.duty(800)                                       # Green ON (comfortable medium)
        pwm5.duty(0)                                         # Blue OFF
    else:                                                    # Bright range
        pwm2.duty(800)                                       # Red ON (warm in bright light)
        pwm4.duty(0)                                         # Green OFF
        pwm5.duty(0)                                         # Blue OFF

    time.sleep(0.2)                                          # Stabilize loop
  • Reflection: Color shifts clearly with light levels.
  • Challenge: Add Yellow (Red+Green) for very bright conditions.

๐ŸŽฎ Microproject 2.10.3 โ€“ Automatic day/night modes

Goal: Switch entire behavior between Night and Day modes using thresholds.

# Automatic day/night modes                                   # Title: mode switching by thresholds

import machine, time                                         # Import required modules

adc32 = machine.ADC(machine.Pin(32))                         # ADC for light sensor
adc32.atten(machine.ADC.ATTN_11DB)                           # 11dB attenuation for broad range
adc32.width(machine.ADC.WIDTH_12BIT)                         # 12-bit ADC resolution

pwm2 = machine.PWM(machine.Pin(2))                           # Red PWM output
pwm4 = machine.PWM(machine.Pin(4))                           # Green PWM output
pwm5 = machine.PWM(machine.Pin(5))                           # Blue PWM output

night_threshold = 1400                                       # Light value below this is Night
day_threshold = 2600                                         # Light value above this is Day
mode = "Day"                                                 # Start in Day mode

print("Day/Night modes ready")                               # Serial start message

while True:                                                  # Continuous check loop
    light = adc32.read()                                     # Read sensor value
    print("Light:", light, "Mode:", mode)                    # Show current reading and mode

    if light < night_threshold:                              # Decide Night mode
        mode = "Night"                                       # Set mode to Night
    elif light > day_threshold:                              # Decide Day mode
        mode = "Day"                                         # Set mode to Day

    if mode == "Night":                                      # Behavior in Night mode
        pwm5.duty(900)                                       # Blue bright for calm night
        pwm4.duty(200)                                       # Green low accent
        pwm2.duty(0)                                         # Red off
    else:                                                    # Behavior in Day mode
        pwm2.duty(900)                                       # Red bright for warm day
        pwm4.duty(600)                                       # Green medium
        pwm5.duty(0)                                         # Blue off

    time.sleep(0.2)                                          # Small delay
  • Reflection: Modes switch cleanly with hysteresis thresholds.
  • Challenge: Add a โ€œSunsetโ€ intermediate mode when light is between thresholds.

๐ŸŽฎ Microproject 2.10.4 โ€“ Smooth color transitions

Goal: Fade LED brightness smoothly up and down.

# Smooth color transitions                                    # Title: fading with incremental steps

import machine, time                                         # Import machine and time

pwm2 = machine.PWM(machine.Pin(2))                           # Red PWM channel
pwm4 = machine.PWM(machine.Pin(4))                           # Green PWM channel
pwm5 = machine.PWM(machine.Pin(5))                           # Blue PWM channel

pwm2.freq(2000)                                              # Optional frequency set
pwm4.freq(2000)                                              # Optional frequency set
pwm5.freq(2000)                                              # Optional frequency set

print("Smooth transition demo")                              # Serial confirmation

for i in range(0, 901, 30):                                  # Fade up steps from 0 to 900
    pwm2.duty(i)                                             # Set Red brightness to i
    pwm4.duty(max(0, 900 - i))                               # Set Green inverse brightness
    pwm5.duty(i // 2)                                        # Set Blue half brightness
    time.sleep(0.05)                                         # Short pause to see transition

for i in range(900, -1, -30):                                # Fade down from 900 to 0
    pwm2.duty(i)                                             # Red down
    pwm4.duty(max(0, 900 - i))                               # Green inverse down
    pwm5.duty(i // 2)                                        # Blue down
    time.sleep(0.05)                                         # Pause per step
  • Reflection: Gradual changes look natural and pleasing.
  • Challenge: Tie the fade speed to light intensity (faster fades in bright light).

๐ŸŽฎ Microproject 2.10.5 โ€“ Custom configuration

Goal: Set thresholds and brightness limits; show them in serial.

# Custom configuration                                        # Title: tweakable settings for behavior

import machine, time                                         # Import machine/time (future use)

night_threshold = 1400                                       # Threshold for Night detection
day_threshold = 2600                                         # Threshold for Day detection
max_brightness = 900                                         # Upper limit for PWM duty
min_brightness = 100                                         # Lower limit for PWM duty
fade_step = 30                                               # Step size for smooth transitions

print("Config loaded")                                       # Confirm settings loaded
print("Night threshold:", night_threshold)                   # Show Night threshold
print("Day threshold:", day_threshold)                       # Show Day threshold
print("Brightness range:", min_brightness, "to", max_brightness) # Show brightness limits
print("Fade step:", fade_step)                               # Show fade step size
  • Reflection: Clear configuration helps teachers and students calibrate easily.
  • Challenge: Add a โ€œprofileโ€ switch (Comfort vs Energy Saver) that changes these values.

โœจ Main Project โ€“ Intelligent Environment Control (complete)

Goal: Combine sensor reading, modes, color mapping, smooth transitions, and custom configs.

# Project 2.10 โ€“ Intelligent Environment Control             # Title: full smart lighting system

import machine, time                                         # Import machine/time for IO and timing

adc32 = machine.ADC(machine.Pin(32))                         # ADC on pin 32 for photoresistor
adc32.atten(machine.ADC.ATTN_11DB)                           # Use 11dB attenuation for broad input range
adc32.width(machine.ADC.WIDTH_12BIT)                         # Set ADC to 12-bit resolution (0โ€“4095)

pwm2 = machine.PWM(machine.Pin(2))                           # Red PWM output on pin 2
pwm4 = machine.PWM(machine.Pin(4))                           # Green PWM output on pin 4
pwm5 = machine.PWM(machine.Pin(5))                           # Blue PWM output on pin 5

pwm2.freq(2000)                                              # Optional PWM frequency (Red)
pwm4.freq(2000)                                              # Optional PWM frequency (Green)
pwm5.freq(2000)                                              # Optional PWM frequency (Blue)

night_threshold = 1400                                       # Night threshold (calibrate in classroom)
day_threshold = 2600                                         # Day threshold (calibrate in classroom)
max_brightness = 900                                         # Max duty to avoid over-bright LEDs
min_brightness = 100                                         # Min duty for visible dim light
fade_step = 30                                               # Fade step for smooth transitions
mode = "Day"                                                 # Start in Day mode

print("Intelligent Environment Control ready")               # Serial start message

while True:                                                  # Main control loop
    light = adc32.read()                                     # Read current light value (0โ€“4095)
    print("Light:", light, "Mode:", mode)                    # Show reading and current mode

    if light < night_threshold:                              # If light indicates night
        mode = "Night"                                       # Switch to Night mode
    elif light > day_threshold:                              # If light indicates day
        mode = "Day"                                         # Switch to Day mode
    else:                                                    # Between thresholds
        mode = "Transition"                                  # Use Transition mode

    if mode == "Night":                                      # Night behavior (cool calm)
        target_r = min_brightness                            # Red low
        target_g = min_brightness                            # Green low
        target_b = max_brightness                            # Blue high
    elif mode == "Day":                                      # Day behavior (warm bright)
        target_r = max_brightness                            # Red high
        target_g = max_brightness // 2                       # Green medium
        target_b = 0                                         # Blue off
    else:                                                    # Transition behavior (balanced)
        target_r = max_brightness // 2                       # Red medium
        target_g = max_brightness // 2                       # Green medium
        target_b = max_brightness // 3                       # Blue low

    current_r = 0                                            # Start current Red duty (simple demo)
    current_g = 0                                            # Start current Green duty
    current_b = 0                                            # Start current Blue duty

    while current_r != target_r or current_g != target_g or current_b != target_b:  # Fade loop until targets
        current_r = current_r + fade_step if current_r < target_r else max(target_r, current_r - fade_step)  # Step Red
        current_g = current_g + fade_step if current_g < target_g else max(target_g, current_g - fade_step)  # Step Green
        current_b = current_b + fade_step if current_b < target_b else max(target_b, current_b - fade_step)  # Step Blue

        current_r = min(max(0, current_r), max_brightness)   # Clamp Red within limits
        current_g = min(max(0, current_g), max_brightness)   # Clamp Green within limits
        current_b = min(max(0, current_b), max_brightness)   # Clamp Blue within limits

        pwm2.duty(current_r)                                  # Apply Red duty
        pwm4.duty(current_g)                                  # Apply Green duty
        pwm5.duty(current_b)                                  # Apply Blue duty

        time.sleep(0.04)                                      # Small delay for smooth fade

    time.sleep(0.2)                                           # Rest before next sensor read

๐Ÿ“– External Explanation

  • What it teaches: Reading analog sensors, mapping values, using thresholds for modes, and PWM for color/brightness.
  • Why it works: The photoresistor provides a light value; thresholds pick modes; PWM sets smooth brightness; the loop keeps adapting.
  • Key concept: Sensor inputs guide outputs in real time using readable, adjustable parameters.

โœจ Story Time

Imagine your room after sunset: lights gently fade cooler as darkness grows, and at dawn they warm up again. Your robot becomes a small โ€œambience artist,โ€ tuning colors to the worldโ€™s rhythm.


๐Ÿ•ต๏ธ Debugging (2)

๐Ÿž Debugging 2.10.A โ€“ Sudden changes in color

  • Symptom: Colors jump abruptly when light moves around thresholds.
  • Cause: Target values applied instantly with no fade or narrow thresholds.
  • Fix:
fade_step = 20                                 # Use smaller steps for smoother changes
time.sleep(0.04)                               # Keep short delays to see gradual transitions

๐Ÿž Debugging 2.10.B โ€“ It does not adapt to conditions

  • Symptom: Lights stay in one mode or brightness feels wrong.
  • Cause: Thresholds not calibrated for classroom hardware/lighting.
  • Fix:
night_threshold = 1600                          # Raise/lower Night threshold after testing
day_threshold = 2400                            # Adjust Day threshold for reliable switching
print("Light:", adc32.read())                   # Print values and tune thresholds accordingly

โœ… Final Checklist

  • Photoresistor reads stable values (printed in serial).
  • RGB channels respond and change duty correctly.
  • Modes switch between Night/Day/Transition as expected.
  • Fades are smooth without sudden jumps.
  • Configuration values are visible and adjustable.

๐Ÿ“š Extras

  • ๐Ÿง  Student tip: Note typical light values in your room (morning, noon, evening) to set good thresholds.
  • ๐Ÿง‘โ€๐Ÿซ Instructor tip: Run a threshold calibration exercise; have learners plot sensor values over time.
  • ๐Ÿ“– Glossary: ADC, attenuation, resolution, PWM, duty, threshold, fade.
  • ๐Ÿ’ก Mini tips:
    • Keep duty under 900 to avoid LED glare.
    • Add a โ€œComfortโ€ profile with warmer colors in Night mode.
    • Print mode changes to help students see state transitions.
On this page