Understanding the GU light sensor

What ho fellow piratical types!

I’m tinkering with my galactic unicorn, reading the light values from the onboard sensor. It’s all very exciting. I’m using the following code:

import time
from galactic import GalacticUnicorn
from picographics import PicoGraphics, DISPLAY_GALACTIC_UNICORN

gu = GalacticUnicorn()
graphics = PicoGraphics(display=DISPLAY_GALACTIC_UNICORN)

WIDTH = GalacticUnicorn.WIDTH
HEIGHT = GalacticUnicorn.HEIGHT

gu.set_brightness(0.3)
gu.clear()

while True:
    light = gu.light()
    print(light)
    time.sleep(10)
    

Looking at the readme.md the value returned is between 0 and 4095. Or if preferred, 256 steps of 16.

Looking at the schematic the component is:
gu-light-sensor

I have a ltr-559, the bh1745 and the as7262. This component is clearly not one of these devices. But I’d like a deeper understanding of what I looking at here, please.

Is this value representing a standardised SI unit. Lux, Lumen etc. Or is it an arbitrary value on the fixed scale of 0 - 4095? What does this component identify as, and does it have any other functions available?

Thanks in advance for any insight you maybe able to share.

Happy tinkering!

1 Like

This may help. It’s a very simple light sensor.
Phototransistors: What Are They & How Do They Work? | Electrical4U

It is very simple and basic with no calibration. It just gives a simple dynamic input value to play with.

As suspected. Thank you to both 🫡

I just sat down with the intent of adding an auto brightness feature to my Galactic Unicorn. Dim it in low background light conditions, and go bright when the room is brightly lit. I was surprised to not find any light sensor example on Pimoroni’s Github page?
Luckily a search brought me back here, and to some nice working code I can start with. Many thanks for posting it. =)

1 Like

Ah, excellent. Very good. Please do share how you got on. 👍️

Wall of code to follow. This is on my Tufty. I wanted to get it working there first, then try modifying it to run on my GU. The file I started with I got here.
pimoroni-pico/micropython/examples/tufty2040 at main · pimoroni/pimoroni-pico (github.com)

Will be having a go at my GU some time today, hopefully.

import time
import machine
import picographics
import micropython

from picographics import PicoGraphics, DISPLAY_TUFTY_2040, PEN_RGB332
display = PicoGraphics(display=DISPLAY_TUFTY_2040, rotate=180, pen_type=PEN_RGB332)
display.set_backlight(1.0)
display.set_font("bitmap8")

BACKLIGHT_LOW = micropython.const(0.375)
BACKLIGHT_HIGH = micropython.const(1.0)

LUMINANCE_LOW = micropython.const(384)
LUMINANCE_HIGH = micropython.const(3072)  # 65535 to use the full range.

from machine import ADC, Pin

# set up the ADCs for measuring battery voltage
vbat_adc = ADC(29)
vref_adc = ADC(28)
vref_en = Pin(27)
vref_en.init(Pin.OUT)
vref_en.value(0)
usb_power = Pin(24, Pin.IN)

full_battery = 4.5
empty_battery = 2.5

# Setup light sensor
lux_vref_pwr = Pin(27, Pin.OUT)
lux = ADC(26)


from pimoroni import Button
button_a = Button(7, invert=False)
button_b = Button(8, invert=False)
button_c = Button(9, invert=False)
button_up = Button(22, invert=False)
button_down = Button(6, invert=False)
button_boot = Button(23, invert=True)

white = display.create_pen(255,255,255)
black = display.create_pen(0,0,0)
red = display.create_pen(255,0,0)
green = display.create_pen(0,255,0)
blue = display.create_pen(0,0,255)
yellow = display.create_pen(255,255,0)
orange = display.create_pen(255,140,0)

WIDTH, HEIGHT = display.get_bounds()

display.set_pen(black)
display.clear()

def auto_brightness(previous: float) -> (float, float):
    luminance = lux.read_u16()
    if button_up.is_pressed:  # Debug key.
        luminance = 65535
    luminance_frac = max(0.0, float(luminance - LUMINANCE_LOW))
    luminance_frac = min(1.0, luminance_frac / (LUMINANCE_HIGH - LUMINANCE_LOW))
    backlight = BACKLIGHT_LOW + (luminance_frac * (BACKLIGHT_HIGH - BACKLIGHT_LOW))
    # Use the previous value to smooth out changes to reduce flickering.
    # The "32" value here controls how quickly it reacts (larger = slower).
    # The rate at which the main loop calls us also affects that!
    backlight_diff = backlight - previous
    backlight = previous + (backlight_diff * (1.0 / 8.0))
    #backlight = previous + (backlight_diff * (1.0 / 32.0))
    return (luminance, backlight)

backlight = BACKLIGHT_LOW

start_time = time.time()
    
while True:
    

    # Turn on VREF and LUX only while we measure things.
    lux_vref_pwr.value(1)
    (luminance, backlight) = auto_brightness(backlight)
    lux_vref_pwr.value(0)

    # Set the new backlight value.
    display.set_backlight(backlight)
    
    print(backlight)
    print(luminance)

I just did this code up, appears to be working, hasn’t crashed anyway.
Another wall of code though.
Will have to wait until it gets dark to see if I need to tweak some values.

import time
import machine
import micropython
from galactic import GalacticUnicorn
from picographics import PicoGraphics, DISPLAY_GALACTIC_UNICORN as DISPLAY

gu = GalacticUnicorn()
graphics = PicoGraphics(DISPLAY)
width = GalacticUnicorn.WIDTH
height = GalacticUnicorn.HEIGHT
#gu.set_brightness(0.1)
graphics.set_font("bitmap8")

BACKLIGHT_LOW = micropython.const(0.375)
BACKLIGHT_HIGH = micropython.const(1.0)

LUMINANCE_LOW = micropython.const(384)
LUMINANCE_HIGH = micropython.const(2048)  # 65535 to use the full range.



SWITCH_A               =  0
SWITCH_B               =  1
SWITCH_C               =  3
SWITCH_D               =  6
SWITCH_SLEEP           = 27
SWITCH_VOLUME_UP       =  7
SWITCH_VOLUME_DOWN     =  8
SWITCH_BRIGHTNESS_UP   = 21
SWITCH_BRIGHTNESS_DOWN = 26

t_color = graphics.create_pen(0,0,0)
h_color = graphics.create_pen(0,0,0)
p_color = graphics.create_pen(0,0,0)
black = graphics.create_pen(0,0,0)
red = graphics.create_pen(255,0,0)
green = graphics.create_pen(0,255,0)
blue = graphics.create_pen(0,0,255)
yellow = graphics.create_pen(255,255,0)
orange = graphics.create_pen(255,140,0)
white = graphics.create_pen(0,255,255)

graphics.set_pen(black)
graphics.clear()

from breakout_bme280 import BreakoutBME280
from pimoroni_i2c import PimoroniI2C

i2c = PimoroniI2C(sda=(4), scl=(5))
bme = BreakoutBME280(i2c)
temperature, pressure, humidity = bme.read()
pressure = pressure / 100      
temperature = round(temperature)
humidity = round(humidity)
pressuremb = round(pressure)
time.sleep(0.5)

from breakout_rtc import BreakoutRTC
from machine import RTC
RV3028 = BreakoutRTC(i2c)
rtc = BreakoutRTC(i2c)
if rtc.is_12_hour:
    rtc.set_24_hour()
RV3028.update_time()
hour = rtc.get_hours()
minute = rtc.get_minutes()
month = rtc.get_month()
date = rtc.get_date()    
weekday = rtc.get_weekday()

if rtc.read_periodic_update_interrupt_flag():
    rtc.clear_periodic_update_interrupt_flag()

if rtc.update_time():
    rtc_date = rtc.string_date()
    rtc_time = rtc.string_time()


def button():
    '''
    if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_UP):
        gu.adjust_brightness(+0.1)

    if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_DOWN):
        gu.adjust_brightness(-0.1)
    '''     
    if gu.is_pressed(GalacticUnicorn.SWITCH_SLEEP):
        graphics.set_pen(black)
        graphics.clear()
        gu.update(graphics)
        machine.deepsleep()        
    ''' 
    if gu.is_pressed(GalacticUnicorn.SWITCH_A):
        gu.set_brightness(0.9)        

    if gu.is_pressed(GalacticUnicorn.SWITCH_B):
        gu.set_brightness(0.7)
        
    if gu.is_pressed(GalacticUnicorn.SWITCH_C):
        gu.set_brightness(0.5)        

    if gu.is_pressed(GalacticUnicorn.SWITCH_D):
        gu.set_brightness(0.3)                
    '''
    return button
    gu.update(graphics)

    
def describe_month(month):
    month = rtc.get_month()
    if month == 1:
        description = "January"
    elif month == 2:
        description = "February"  
    elif month == 3:
        description = "March"
    elif month == 4:
        description = "April"              
    elif month == 5:
        description = "May"              
    elif month == 6:
        description = "June"              
    elif month == 7:
        description = "July"              
    elif month == 8:
        description = "August"              
    elif month == 9:
        description = "September"
    elif month == 10:
        description = "October"             
    elif month == 11:
        description = "November"              
    elif month == 12:
        description = "December"            
    return description


def describe_date(date):
    date = rtc.get_date()
    if date == 1:
        description = "st"
    elif date == 2:
        description = "nd"     
    elif date == 3:
        description = "rd" 
    elif date == 21:
        description = "st"      
    elif date == 22:
        description = "nd"  
    elif date == 23:
        description = "rd"
    elif date == 31:
        description = "st"
    else:
        description = "th"
    return description


def describe_temperature(temperature):
    global t_color
    if temperature < -10:
        description = " Cold"
        t_color = white
    elif -10 <= temperature <= 0:
        description = " Cold"
        t_color = blue
    elif 0 < temperature <= 12:
        description = " Cool"
        t_color = yellow
    elif 12 < temperature <= 16:
        description = " Warm"
        t_color = green
    elif 16 < temperature <= 24:
        description = ""
        t_color = green      
    elif 24 < temperature <= 27:
        description = " Hot"
        t_color = orange
    elif temperature > 27:
        description = " Hot+"
        t_color = red
    return description


def describe_humidity(humidity):
    global h_color
    if humidity < 30:
        description = " Low"
        h_color = red
    elif 30 <= humidity <= 60:
        description = ""
        h_color = green
    elif 60 < humidity < 80:
        description = " High"
        h_color = yellow
    elif humidity >= 80:
        description = " High"
        h_color = orange        
    return description


def describe_pressure(pressuremb):
    global p_color
    if pressuremb < 982:
        description = "-Low-"
        p_color = red
    elif 982 <= pressuremb < 1004:
        description = "Low"
        p_color = yellow
    elif 1004 <= pressuremb < 1026:
        description = ""
        p_color = green
    elif 1026 <= pressuremb < 1048:
        description = "High"
        p_color = blue
    elif pressuremb >= 1048:
        description = "+High+"
        p_color = orange
    return description

def auto_brightness(previous: float) -> (float, float):
    luminance = gu.light()
    luminance_frac = max(0.0, float(luminance - LUMINANCE_LOW))
    luminance_frac = min(1.0, luminance_frac / (LUMINANCE_HIGH - LUMINANCE_LOW))
    backlight = BACKLIGHT_LOW + (luminance_frac * (BACKLIGHT_HIGH - BACKLIGHT_LOW))
    # Use the previous value to smooth out changes to reduce flickering.
    # The "32" value here controls how quickly it reacts (larger = slower).
    # The rate at which the main loop calls us also affects that!
    backlight_diff = backlight - previous
    backlight = previous + (backlight_diff * (1.0 / 8.0))
    return (luminance, backlight)

#gu.set_brightness(BACKLIGHT_LOW)
backlight = BACKLIGHT_LOW

while True:
    luminance = gu.light()
    print(luminance)
    (luminance, backlight) = auto_brightness(backlight)
    gu.set_brightness(backlight)
    print(backlight)
    
    

    
    temperature, pressure, humidity = bme.read()
    pressure = pressure / 100      
    temperature = round(temperature)
    humidity = round(humidity)
    pressuremb = round(pressure)
    time.sleep(0.02)
    
    RV3028.update_time()
    hour = rtc.get_hours()
    minute = rtc.get_minutes()
    month = rtc.get_month()
    date = rtc.get_date()    
    weekday = rtc.get_weekday()
    
    if rtc.read_periodic_update_interrupt_flag():
        rtc.clear_periodic_update_interrupt_flag()

    if rtc.update_time():
        rtc_date = rtc.string_date()
        rtc_time = rtc.string_time()
        

    graphics.set_pen(white)
   
    if hour == 0:
        graphics.text(f"{12}:{minute:02}AM", 0, 2, scale=1)    
    elif 0 <= hour < 10:
        graphics.text(f"{hour:1}:{minute:02}AM", 0, 2, scale=1)
    elif 10 <= hour < 12:
        graphics.text(f"{hour:2}:{minute:02}AM", 0, 2, scale=1)
    elif hour == 12:
        graphics.text(f"{hour:2}:{minute:02}PM", 0, 2, scale=1)    
    elif hour > 12:
        hour = hour - 12
        if hour < 10:
            graphics.text(f"{hour:1}:{minute:02}PM", 0, 2, scale=1)
        elif 10 <= hour < 12:
            graphics.text(f"{hour:2}:{minute:02}PM", 0, 2, scale=1)
        elif hour == 12:
            graphics.text(f"{hour:2}:{minute:02}AM", 0, 2, scale=1)
            
            
    
    #button()

    gu.update(graphics)
    
    time.sleep(3)
    
    graphics.set_pen(black)
    graphics.clear()

    graphics.set_pen(white)
    
    if weekday == 0:
        graphics.text("Monday", 0, 2, scale=1)        
    if weekday == 1:
        graphics.text("Tuesday", 0, 2, scale=1)
    if weekday == 2:
        graphics.text("Wednesday", 0, 2, scale=1)
    if weekday == 3:
        graphics.text("Thursday", 0, 2, scale=1)
    if weekday == 4:
        graphics.text("Friday", 0, 2, scale=1)
    if weekday == 5:
        graphics.text("Saturday", 0, 2, scale=1)
    if weekday == 6:
        graphics.text("Sunday", 0, 2, scale=1)        

    button()

    gu.update(graphics)
    
    time.sleep(3)
    
    graphics.set_pen(black)
    graphics.clear()

    graphics.set_pen(white)
    describe_month(month)
    graphics.text(f"{describe_month(month)} {date}{describe_date(date)}", 0, 2, scale=1)     

    button()

    gu.update(graphics)    
    
    time.sleep(3)

    graphics.set_pen(black)
    graphics.clear()    
    
    describe_temperature(temperature)
    graphics.set_pen(t_color)
    graphics.text("{:0.0f}°C" .format(temperature), 0, 2, scale=1)
    graphics.text(describe_temperature(temperature), 20, 2, scale=1)

    button()

    gu.update(graphics)         
    
    time.sleep(3)
    
    graphics.set_pen(black)
    graphics.clear()
    
    describe_humidity(humidity)
    graphics.set_pen(h_color)
    graphics.text("{:0.0f}%" .format(humidity), 0, 2, scale=1)
    graphics.text(describe_humidity(humidity), 16, 2, scale=1)

    button()

    gu.update(graphics)         
    
    time.sleep(3)
       
    graphics.set_pen(black)
    graphics.clear()
    
    describe_pressure(pressuremb)
    
    graphics.set_pen(p_color)
    graphics.text("{:0.0f}mb" .format(pressuremb), 0, 2, scale=1)
    graphics.text(describe_pressure(pressuremb), 30, 2, scale=1)

    button()

    gu.update(graphics)
        
    time.sleep(3)
    
    graphics.set_pen(black)
    graphics.clear()        
 
    gu.update(graphics)
    
    # pause for a moment (important or the USB serial device will fail)
    time.sleep(0.001)

This just the auto brightness code. Sorry for not cleaning the junk out of the other files.
Hoping I didn’t miss something needed.
It starts in Auto mode.
Pressing any button except A puts it in manual mode.
B is bright, C is mid range, and D is low.
The arrow keys will adjust it up or down from there.
Pressing A puts it back into Auto mode.
Pressing the Sleep button puts it into Deep Sleep (turns it off)
Pressing Reset turns it back on if in Deep Sleep.

import time
import machine
import micropython
from galactic import GalacticUnicorn
from picographics import PicoGraphics, DISPLAY_GALACTIC_UNICORN as DISPLAY

gu = GalacticUnicorn()
graphics = PicoGraphics(DISPLAY)
width = GalacticUnicorn.WIDTH
height = GalacticUnicorn.HEIGHT

BACKLIGHT_LOW = micropython.const(0.1)
BACKLIGHT_HIGH = micropython.const(1.0)

LUMINANCE_LOW = micropython.const(128)
LUMINANCE_HIGH = micropython.const(1024)  # 3072 to use the full range.

A = 1

SWITCH_A               =  0
SWITCH_B               =  1
SWITCH_C               =  3
SWITCH_D               =  6
SWITCH_SLEEP           = 27
SWITCH_VOLUME_UP       =  7
SWITCH_VOLUME_DOWN     =  8
SWITCH_BRIGHTNESS_UP   = 21
SWITCH_BRIGHTNESS_DOWN = 26


black = graphics.create_pen(0,0,0)
red = graphics.create_pen(255,0,0)
green = graphics.create_pen(0,255,0)
blue = graphics.create_pen(0,0,255)
yellow = graphics.create_pen(255,255,0)
orange = graphics.create_pen(255,140,0)
white = graphics.create_pen(0,255,255)

graphics.set_pen(black)
graphics.clear()


def button():
    
    if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_UP):
        A == 0
        gu.adjust_brightness(+0.1)

    if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_DOWN):
        A == 0
        gu.adjust_brightness(-0.1)
         
    if gu.is_pressed(GalacticUnicorn.SWITCH_SLEEP):
        graphics.set_pen(black)
        graphics.clear()
        gu.update(graphics)
        machine.deepsleep()        
     
    if gu.is_pressed(GalacticUnicorn.SWITCH_A):
        A == 1        

    if gu.is_pressed(GalacticUnicorn.SWITCH_B):
        A == 0
        gu.set_brightness(0.7)
        
    if gu.is_pressed(GalacticUnicorn.SWITCH_C):
        A == 0
        gu.set_brightness(0.5)        

    if gu.is_pressed(GalacticUnicorn.SWITCH_D):
        A == 0
        gu.set_brightness(0.1)                
    
    return button
    gu.update(graphics)

    

def auto_brightness(previous: float) -> (float, float):
    luminance = gu.light()
    luminance_frac = max(0.0, float(luminance - LUMINANCE_LOW))
    luminance_frac = min(1.0, luminance_frac / (LUMINANCE_HIGH - LUMINANCE_LOW))
    backlight = BACKLIGHT_LOW + (luminance_frac * (BACKLIGHT_HIGH - BACKLIGHT_LOW))
    # Use the previous value to smooth out changes to reduce flickering.
    # The "32" value here controls how quickly it reacts (larger = slower).
    # The rate at which the main loop calls us also affects that!
    backlight_diff = backlight - previous
    backlight = previous + (backlight_diff * (1.0 / 8.0))
    return (luminance, backlight)

#gu.set_brightness(BACKLIGHT_LOW)
backlight = BACKLIGHT_LOW

while True:
    
    if A == 1:
        luminance = gu.light()
        (luminance, backlight) = auto_brightness(backlight)
        gu.set_brightness(backlight)
        
    button()

    gu.update(graphics)
    
 
    
    # pause for a moment (important or the USB serial device will fail)
    time.sleep(0.001)

You’ve been busy!

Will try this out on my GU later.

Going to try porting it to my Interstate 75 W latter on today.

My GU pretty well runs 24/7, and the light in that room goes from very dark at night to bright during the day. It’s nice not having to go poke buttons to turn it down at night. It can be very distracting when brightly lit up in a dark room.

Same deal with my Tufty. It sits on my bedside table displaying weather data. I like it very dim at night. Just bright enough to read. During the day though, you need to turn it up to 11. =)

Hmm, looking at the Function Reference for the Interstate 75 W, I’m not seeing any backlight / display brightness function? That may be harder than I thought?
I have an LTR-559 wired up and working, just need a way to control the array brightness?

Somethings not right? I could have sworn I had it all working as intended.

Something keeps putting it back in auto mode every time it goes back to the top of the while true code. As soon as the time goes up its back in auto?

EDIT: Looks like it was in my button code. I had to make A a global variable.

def button():
   
    if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_UP):
        global A
        A = 0
        gu.adjust_brightness(+0.1)

    if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_DOWN):
        global A
        A = 0
        gu.adjust_brightness(-0.1)
         
    if gu.is_pressed(GalacticUnicorn.SWITCH_SLEEP):
        graphics.set_pen(black)
        graphics.clear()
        gu.update(graphics)
        machine.deepsleep()        
     
    if gu.is_pressed(GalacticUnicorn.SWITCH_A):
        global A
        A = 1        
    
    if gu.is_pressed(GalacticUnicorn.SWITCH_B):
        global A 
        A = 0
        gu.set_brightness(0.7)
        
    if gu.is_pressed(GalacticUnicorn.SWITCH_C):
        global A
        A = 0
        gu.set_brightness(0.5)        

    if gu.is_pressed(GalacticUnicorn.SWITCH_D):
        global A
        A = 0
        gu.set_brightness(0.1)                
    
    return button