diff --git a/micropython/examples/cosmic_unicorn/README.md b/micropython/examples/cosmic_unicorn/README.md index 3bd30301..0543307d 100644 --- a/micropython/examples/cosmic_unicorn/README.md +++ b/micropython/examples/cosmic_unicorn/README.md @@ -9,6 +9,7 @@ - [Feature Test With Audio](#feature-test-with-audio) - [Fire Effect](#fire-effect) - [Lava Lamp](#lava-lamp) + - [Light Sensor](#light-sensor) - [Nostalgia Prompt](#nostalgia-prompt) - [Rainbow](#rainbow) - [Scrolling Text](#scrolling-text) @@ -85,6 +86,14 @@ A pretty, procedural fire effect. Switch between landscape fire and vertical fir A 70s-tastic, procedural rainbow lava lamp. You can adjust the brightness with LUX + and -. +### Light Sensor + +[light_sensor.py](light_sensor.py) + +Reads data from the on board light sensor and displays the brightness level of the environment. The display is by default set to auto brightness i.e reacts to the brightness of the environment. +- Button A turns auto brightness off +- Button B turns auto brightness on + ### Nostalgia Prompt [nostalgia_prompt.py](nostalgia_prompt.py) diff --git a/micropython/examples/cosmic_unicorn/light_sensor.py b/micropython/examples/cosmic_unicorn/light_sensor.py new file mode 100644 index 00000000..46c89a0a --- /dev/null +++ b/micropython/examples/cosmic_unicorn/light_sensor.py @@ -0,0 +1,164 @@ +import time +from cosmic import CosmicUnicorn +from picographics import PicoGraphics, DISPLAY_COSMIC_UNICORN as DISPLAY + +""" +Light sensoring feature for the cosmic unicorn +Uses the onboard light sensor to detect the light in the environment +The brightness level is displayed as percentage. +Brightness of the display is auto adjusted to the brightness level of the environment +Press A to turn auto brightness on +Press B to turn auto brightness off +""" +# set up unicorn and drawing variables +cu = CosmicUnicorn() +graphics = PicoGraphics(DISPLAY) + +WIDTH, HEIGHT = graphics.get_bounds() +BLACK = graphics.create_pen(0, 0, 0) +WHITE = graphics.create_pen(255, 255, 255) +GREY = graphics.create_pen(20, 20, 20) +HUE_START = 0 +HUE_END = 100 +graphics.set_font("bitmap8") + +# Text display sleep time in ms +TEXT_SLEEP = 500 + + +# the onboard light sensor has a wide range from 0 t0 4095 +# It is therefore needed to set a lower max and a higher minimum +MIN_LS_VALUE = 10 +MAX_LS_VALUE = 295 # 4095 to use the full range +MIN_RANGE = 0.1 +MAX_RANGE = 1 + +# Rate of display change i.e the lower the value the slower the transition +TRANSITION_RATE = 1.0 / 72.0 + +# perform linear interpolation to map a range of values to discrete +def map_range( + x, + min_input=MIN_LS_VALUE, + max_input=MAX_LS_VALUE, + min_output=MIN_RANGE, + max_output=MAX_RANGE, +): + return (x - min_input) * (max_output - min_output) / ( + max_input - min_input + ) + min_output + + +# gets the light sensor value from onboard sensor and interpolates it +# clamps the brightness value it outside the ranges specified +def calculate_brightness(prev_brightness_val): + current_lsv = cu.light() + current_brightness_val = map_range(current_lsv) + + # uses the previous value to smooth out display changes reducing flickering + brightness_diff = current_brightness_val - prev_brightness_val + brightness_val = prev_brightness_val + (brightness_diff * TRANSITION_RATE) + if brightness_val > 1: + brightness_val = 1 + elif brightness_val < 0.1: + brightness_val = 0.1 + + return brightness_val + + +# sets up a handy function we can call to clear the screen +def clear(): + graphics.set_pen(BLACK) + graphics.clear() + + +def draw_percentage(x, y): + graphics.rectangle(x + 1, y + 1, 2, 2) + graphics.line(x + 1, y + 5, x + 6, y) + graphics.rectangle(x + 4, y + 4, 2, 2) + + +# draws a sun icon +def draw_sun(x, y, r): + circle_x = x + 3 + r + circle_y = y + 3 + r + graphics.circle(circle_x, circle_y, r) + graphics.line(circle_x, y, circle_x, y + 2) + graphics.line(x, circle_y, x + 2, circle_y) + graphics.line(circle_x, (y + 5 + 2 * r), circle_x, (y + 5 + 2 * r) + 2) + graphics.line((x + 5 + 2 * r), circle_y, (x + 5 + 2 * r) + 2, circle_y) + graphics.line( + circle_x + 1 + r, circle_y - 1 - r, circle_x + 3 + r, circle_y - 3 - r + ) + graphics.line( + circle_x + 1 + r, circle_y + 1 + r, circle_x + 3 + r, circle_y + 3 + r + ) + graphics.line( + circle_x - 1 - r, circle_y - 1 - r, circle_x - 3 - r, circle_y - 3 - r + ) + graphics.line( + circle_x - 1 - r, circle_y + 1 + r, circle_x - 3 - r, circle_y + 3 + r + ) + + +mode = "auto" +last = time.ticks_ms() + +brightness_value = MIN_RANGE # set the initial brightness level to the minimum +while True: + current = time.ticks_ms() + + # set the display brightness + brightness_value = calculate_brightness(brightness_value) + cu.set_brightness(brightness_value) + + bp = (brightness_value / MAX_RANGE) * 100 # gets brightness value in percentage relative to the MAX_LS_VALUE set + + # deactivate auto brightness by pressing A + if cu.is_pressed(CosmicUnicorn.SWITCH_A): + print("Auto brightness off") + mode = "off" + + # reactivate auto brightness by pressing A + if cu.is_pressed(CosmicUnicorn.SWITCH_B): + print("Auto brightness on") + mode = "auto" + + # set brightness to default value if off + if mode == "off": + cu.set_brightness(0.5) + + # set text update rate after a certain time to reduce flickering + if current - last >= TEXT_SLEEP: + clear() + + # calculate colour from the brightness value + hue = max(0, HUE_START + ((bp - 0) * (HUE_END - HUE_START) / (100 - 0))) + + # create pens with this colour (and with the high / low colours) + CURRENT_COLOUR = graphics.create_pen_hsv(hue / 360, 1.0, 0.8) + HIGH_COLOUR = graphics.create_pen_hsv(HUE_END / 360, 1.0, 0.8) + LOW_COLOUR = graphics.create_pen_hsv(HUE_START / 360, 1.0, 0.8) + + # draw the text + graphics.set_pen(CURRENT_COLOUR) + graphics.text("BRT: ", 0, 1, scale=1) + graphics.text(f"{bp:.0f}", 7, 23, scale=1) + draw_percentage((WIDTH - 10), 23) + + # draw sun icon + draw_sun(0, 10, 2) + + # draw a bar for the background + bar_width = WIDTH - 12 + graphics.set_pen(GREY) + graphics.rectangle(13, 10, bar_width, 11) + + # draw a bar for the current brightness percentage + graphics.set_pen(CURRENT_COLOUR) + graphics.rectangle(13, 10, int((bp / 100) * bar_width), 11) + + last = current + + # time to update the display + cu.update(graphics) diff --git a/micropython/examples/galactic_unicorn/README.md b/micropython/examples/galactic_unicorn/README.md index 25149f08..cff373d5 100644 --- a/micropython/examples/galactic_unicorn/README.md +++ b/micropython/examples/galactic_unicorn/README.md @@ -10,6 +10,7 @@ - [Feature Test With Audio](#feature-test-with-audio) - [Fire Effect](#fire-effect) - [Lava Lamp](#lava-lamp) + - [Light Sensor](#light-sensor) - [Nostalgia Prompt](#nostalgia-prompt) - [Rainbow](#rainbow) - [Scrolling Text](#scrolling-text) @@ -88,6 +89,14 @@ A pretty, procedural fire effect. Switch between landscape fire and vertical fir A 70s-tastic, procedural rainbow lava lamp. You can adjust the brightness with LUX + and -. +### Light Sensor + +[light_sensor.py](light_sensor.py) + +Reads data from the on board light sensor and displays the brightness level of the environment. The display is by default set to auto brightness i.e reacts to the brightness of the environment. +- Button A turns auto brightness off +- Button B turns auto brightness on + ### Nostalgia Prompt [nostalgia_prompt.py](nostalgia_prompt.py) diff --git a/micropython/examples/galactic_unicorn/light_sensor.py b/micropython/examples/galactic_unicorn/light_sensor.py index 1b6759d6..2966e09c 100644 --- a/micropython/examples/galactic_unicorn/light_sensor.py +++ b/micropython/examples/galactic_unicorn/light_sensor.py @@ -3,9 +3,12 @@ from galactic import GalacticUnicorn from picographics import PicoGraphics, DISPLAY_GALACTIC_UNICORN as DISPLAY """ -Auto brightness feature for the galactic unicorn -Uses the onboard light sensor to detect the light -The brightness percentage is displayed with brightness auto adjusted +Light sensoring feature for the galactic unicorn +Uses the onboard light sensor to detect the light in the environment +The brightness level is displayed as percentage. +Brightness of the display is auto adjusted to the brightness level of the environment +Press A to turn auto brightness on +Press B to turn auto brightness off """ # set up unicorn and drawing variables gu = GalacticUnicorn() @@ -30,6 +33,9 @@ MAX_LS_VALUE = 295 # 4095 to use the full range MIN_RANGE = 0.1 MAX_RANGE = 1 +# Rate of display change i.e the lower the value the slower the transition +TRANSITION_RATE = 1.0 / 72.0 + # perform linear interpolation to map a range of values to discrete def map_range( @@ -45,9 +51,14 @@ def map_range( # gets the light sensor value from onboard sensor and interpolates it -# clamps the brightness values -def calculate_brightness(current_lsv): - brightness_val = map_range(current_lsv) +# clamps the brightness value it outside the ranges specified +def calculate_brightness(prev_brightness_val): + current_lsv = gu.light() + current_brightness_val = map_range(current_lsv) + + # uses the previous value to smooth out display changes reducing flickering + brightness_diff = current_brightness_val - prev_brightness_val + brightness_val = prev_brightness_val + (brightness_diff * TRANSITION_RATE) if brightness_val > 1: brightness_val = 1 elif brightness_val < 0.1: @@ -56,23 +67,30 @@ def calculate_brightness(current_lsv): return brightness_val +# draws percentage icon +def draw_percentage(x, y): + graphics.rectangle(x + 1, y + 1, 2, 2) + graphics.line(x + 1, y + 5, x + 6, y) + graphics.rectangle(x + 4, y + 4, 2, 2) + + # sets up a handy function we can call to clear the screen def clear(): graphics.set_pen(BLACK) graphics.clear() -mode = "auto" +mode = "auto" # set auto brightness on last = time.ticks_ms() +brightness_value = MIN_RANGE # set the initial brightness level to the specified minimum while True: current = time.ticks_ms() - # get light sensor value from the sensor - ls_value = gu.light() - brightness_value = calculate_brightness(ls_value) + # set the display brightness + brightness_value = calculate_brightness(brightness_value) gu.set_brightness(brightness_value) - # calculate brightness percentage - bp = (brightness_value / MAX_RANGE) * 100 + + bp = (brightness_value / MAX_RANGE) * 100 # gets brightness value in percentage relative to the MAX_LS_VALUE set # deactivate auto brightness by pressing A if gu.is_pressed(GalacticUnicorn.SWITCH_A): @@ -103,9 +121,11 @@ while True: # draw the text graphics.set_pen(CURRENT_COLOUR) graphics.text("BRT: ", 0, 1, scale=1) + # measure the rest of the text before drawing to right align it - text_width = graphics.measure_text(f"{bp:.0f}/°", scale=1) - graphics.text(f"{bp:.0f}%", WIDTH - text_width, 1, scale=1) + text_width = graphics.measure_text(f"{bp:.0f} ", scale=1) + graphics.text(f"{bp:.0f}", WIDTH - text_width, 1, scale=1) + draw_percentage((WIDTH - 8), 1) # draw a bar for the background graphics.set_pen(GREY) @@ -118,4 +138,3 @@ while True: # time to update the display gu.update(graphics) - # time.sleep(1) diff --git a/micropython/examples/stellar_unicorn/README.md b/micropython/examples/stellar_unicorn/README.md index d7c1f788..0f5d6997 100644 --- a/micropython/examples/stellar_unicorn/README.md +++ b/micropython/examples/stellar_unicorn/README.md @@ -9,6 +9,7 @@ - [Feature Test With Audio](#feature-test-with-audio) - [Fire Effect](#fire-effect) - [Lava Lamp](#lava-lamp) + - [Light Sensor](#light-sensor) - [Nostalgia Prompt](#nostalgia-prompt) - [Rainbow](#rainbow) - [Scrolling Text](#scrolling-text) @@ -91,6 +92,14 @@ A pretty, procedural fire effect. Switch between landscape fire and vertical fir A 70s-tastic, procedural rainbow lava lamp. You can adjust the brightness with LUX + and -. +### Light Sensor + +[light_sensor.py](light_sensor.py) + +Reads data from the on board light sensor and displays the brightness level of the environment. The display is by default set to auto brightness i.e reacts to the brightness of the environment. +- Button A turns auto brightness off +- Button B turns auto brightness on + ### Nostalgia Prompt [nostalgia_prompt.py](nostalgia_prompt.py) diff --git a/micropython/examples/stellar_unicorn/light_sensor.py b/micropython/examples/stellar_unicorn/light_sensor.py new file mode 100644 index 00000000..d2aec759 --- /dev/null +++ b/micropython/examples/stellar_unicorn/light_sensor.py @@ -0,0 +1,142 @@ +import time +from stellar import StellarUnicorn +from picographics import PicoGraphics, DISPLAY_STELLAR_UNICORN as DISPLAY + +""" +Light sensoring feature for the stellar unicorn +Uses the onboard light sensor to detect the light in the environment +The brightness level is displayed as percentage. +Brightness of the display is auto adjusted to the brightness level of the environment +Press A to turn auto brightness on +Press B to turn auto brightness off +""" +# set up unicorn and drawing variables +su = StellarUnicorn() +graphics = PicoGraphics(DISPLAY) + +WIDTH, HEIGHT = graphics.get_bounds() +BLACK = graphics.create_pen(0, 0, 0) +WHITE = graphics.create_pen(255, 255, 255) +GREY = graphics.create_pen(20, 20, 20) +HUE_START = 0 +HUE_END = 100 +graphics.set_font("bitmap8") + +# Text display sleep time in ms +TEXT_SLEEP = 500 + + +# the onboard light sensor has a wide range from 0 t0 4095 +# It is therefore needed to set a lower max and a higher minimum +MIN_LS_VALUE = 10 +MAX_LS_VALUE = 295 # 4095 to use the full range +MIN_RANGE = 0.1 +MAX_RANGE = 1 + +# Rate of display change i.e the lower the value the slower the transition +TRANSITION_RATE = 1.0 / 72.0 + + +# perform linear interpolation to map a range of values to discrete +def map_range( + x, + min_input=MIN_LS_VALUE, + max_input=MAX_LS_VALUE, + min_output=MIN_RANGE, + max_output=MAX_RANGE, +): + return (x - min_input) * (max_output - min_output) / ( + max_input - min_input + ) + min_output + + +# gets the light sensor value from onboard sensor and interpolates it +# clamps the brightness value it outside the ranges specified +def calculate_brightness(prev_brightness_val): + current_lsv = su.light() + current_brightness_val = map_range(current_lsv) + + # uses the previous value to smooth out display changes reducing flickering + brightness_diff = current_brightness_val - prev_brightness_val + brightness_val = prev_brightness_val + (brightness_diff * TRANSITION_RATE) + if brightness_val > 1: + brightness_val = 1 + elif brightness_val < 0.1: + brightness_val = 0.1 + + return brightness_val + + +# draws percentage icon +def draw_percentage(x, y): + graphics.rectangle(x + 1, y + 1, 2, 2) + graphics.line(x + 1, y + 5, x + 6, y) + graphics.rectangle(x + 4, y + 4, 2, 2) + + +# sets up a handy function we can call to clear the screen +def clear(): + graphics.set_pen(BLACK) + graphics.clear() + + +mode = "auto" +last = time.ticks_ms() +brightness_value = MIN_RANGE # set the initial brightness level to the specified minimum +while True: + current = time.ticks_ms() + + # set the display brightness + brightness_value = calculate_brightness(brightness_value) + su.set_brightness(brightness_value) + + bp = (brightness_value / MAX_RANGE) * 100 # gets brightness value in percentage relative to the MAX_LS_VALUE set + + # calculate brightness percentage + bp = (brightness_value / MAX_RANGE) * 100 + + # deactivate auto brightness by pressing A + if su.is_pressed(StellarUnicorn.SWITCH_A): + print("Auto brightness off") + mode = "off" + + # reactivate auto brightness by pressing A + if su.is_pressed(StellarUnicorn.SWITCH_B): + print("Auto brightness on") + mode = "auto" + + # set brightness to default value if off + if mode == "off": + su.set_brightness(0.5) + + # set text update rate after a certain time to reduce flickering + if current - last >= TEXT_SLEEP: + clear() + + # calculate colour from the brightness value + hue = max(0, HUE_START + ((bp - 0) * (HUE_END - HUE_START) / (100 - 0))) + + # create pens with this colour (and with the high / low colours) + CURRENT_COLOUR = graphics.create_pen_hsv(hue / 360, 1.0, 0.8) + HIGH_COLOUR = graphics.create_pen_hsv(HUE_END / 360, 1.0, 0.8) + LOW_COLOUR = graphics.create_pen_hsv(HUE_START / 360, 1.0, 0.8) + + # draw the text + graphics.set_pen(CURRENT_COLOUR) + graphics.text(f"{bp:.0f}", 0, 1, scale=1) + # measure the rest of the text before drawing to right align it + text_width = graphics.measure_text(f"{bp:.0f}/°", scale=1) + + draw_percentage(10, 1) + + # draw a bar for the background + graphics.set_pen(GREY) + graphics.rectangle(0, 9, WIDTH, 10) + + # draw a bar for the current brightness percentage + graphics.set_pen(CURRENT_COLOUR) + graphics.rectangle(0, 9, int((bp / 100) * WIDTH), 10) + last = current + + # update the display + su.update(graphics)