Guess what I built?

I’ve been tinkering with this for a while now. Trying to up my game a little bit code wise.
Really happy with how it looks. Kind of interested as to what you all think of it?
What the colors mean etc. I know because I coded it. ;)

All the bits with silicon on them are Pimoroni Originals. ;)
So any guesses as to what hardware I used?
Pi or Pico etc?
Python or Micro Python etc?

Capture

Capture2

2 Likes

I love the way it looks and the colors, though I have no idea what it’s made with!

I didn’t want to give to much away in the photos. I will add one with more detail when I get a chance.

The display is a 320 x 240 IPS LCD Display with 4 buttons and an RGB LED. There is also a BME280 to gather the data. It’s a little chunky but I can put it in my coat pocket. It can run off of battery.

I’ll chuck my ticket into the hat as a cautious opening gambit. Hoping I might win a prize!

A tufty2040, running micropython, a lipo, replete with a battery. Two display options, toggled by a button push for Indoor and outdoor values. Colours denote value ranges and definitions. Possibly some WiFi connectivity involved too?

I will now sit on the edge of my seat, refreshing this thread constantly, to see how wrong I got it all. Not apprehensive at all, no not me.

1 Like

It not a Tufty, but you’re not far off. It is in a way a Tufty Clone. I built it before there was a Tufty. I have a Tufty here running a slightly modified version of that code.

I’ll try and get some good pics up latter on today.

It’s a Pimoroni Pico Lipo 16mb with a Lipo Battery attached. Pico Display Pack V2, RV3028 RTC, and BME280. No WIFI.
The color of the descriptor matches where the indicator is. And the color denotes conditions. Green is OK, yellow not to good, and Red is bad, etc. I went with white for the actual numerical displays as its easier to see and read. For me it is anyway as I’m partially color blind. Trying to read blue text gives me a headache.

The temperature scale goes from -32 to +32, 0c in the middle. On the one I take outside anyway. The Tufty version just sits on my desk and it goes from 0c to +32c. The readings will go past those numbers but the marker stops at the edge of the screen.

def describe_temperature(temperature):
    global t_color
    if temperature < -10:
        description = "Very 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"
        tempcolor = green
    elif 16 < temperature <= 24:
        description = "OK"
        t_color = green      
    elif 24 < temperature <= 27:
        description = "Hot"
        t_color = orange
    elif temperature > 27:
        description = "Very Hot"
        t_color = red
    return description
def draw_graph(temp_value, press_value, humid_value):
    scaled_temp = int((temperature * 5) + 160)
    if scaled_temp <= 9:
        scaled_temp =9
        
    if scaled_temp >= 310:
        scaled_temp =310
    
    describe_temperature(temperature)
    display.set_pen(white)
    display.circle(9, 98, 9)
    display.rectangle(12, 89, 92, 19)
    display.set_pen(blue)
    display.rectangle(106, 89, 53, 19)
    display.set_pen(yellow)
    display.rectangle(161,89,78,19)
    display.set_pen(green)
    display.rectangle(241,89,38,19)
    display.set_pen(orange)
    display.rectangle(281,89,13,19)
    display.set_pen(red)
    display.rectangle(296,89,15,19)
    display.circle(310,98,9)
    display.set_pen(black)
    display.circle((scaled_temp),98,9)
    display.set_pen(white)
    display.circle((scaled_temp),98,5)    
    display.set_pen(t_color)
    display.text(describe_temperature(temperature),150,52,scale=4)    
1 Like

let’s have a look at the whole thing!!

When powered via the USB port the LED is off. On Battery its Green. At 50% remaining capacity it turns yellow, then Red at 20 % remaining. Pressing and holding the B button displays the Battery State. X is Backlight full brightness, Y id backlight at 50% and A is backlight at 20% brightness.




2 Likes

The Tufty doesn’t have a RTC added to it just yet. Where the time and date would be it just displays the Battery State. If plugged into USB power it just says Powered By USB Port.

1 Like

This is the current main.py on the Tufty Clone.

import utime
import picographics
from picographics import PicoGraphics, DISPLAY_PICO_DISPLAY_2, PEN_RGB332
display = PicoGraphics(display=DISPLAY_PICO_DISPLAY_2, rotate=0, pen_type=PEN_RGB332)
display.set_backlight(1.0)
display.set_font("bitmap8") 

from breakout_bme280 import BreakoutBME280
from pimoroni_i2c import PimoroniI2C
i2c = PimoroniI2C(sda=(4), scl=(5))
bme = BreakoutBME280(i2c,0x77)

from breakout_rtc import BreakoutRTC
from machine import RTC
RV3028 = BreakoutRTC(i2c)

rtc = BreakoutRTC(i2c)
if rtc.is_12_hour:
    rtc.set_24_hour()

from machine import ADC, Pin
vsys = ADC(29)
charging = Pin(24, Pin.IN)
conversion_factor = 3 * 3.3 / 65535

full_battery = 4.2    
empty_battery = 3.2          

from pimoroni import Button
button_a = Button(12)
button_b = Button(13)
button_x = Button(14)
button_y = Button(15)

from pimoroni import RGBLED
led = RGBLED(6, 7, 8)
led.set_rgb(0, 0, 0) 

t_color = display.create_pen(0,0,0)
h_color = display.create_pen(0,0,0)
p_color = display.create_pen(0,0,0)


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)
white = display.create_pen(224,224,224)

display.set_pen(black)
display.clear()

# converts the temperature into a description and pen colour
def describe_temperature(temperature):
    global t_color
    if temperature < -10:
        description = "Very 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"
        tempcolor = green
    elif 16 < temperature <= 24:
        description = "OK"
        t_color = green      
    elif 24 < temperature <= 27:
        description = "Hot"
        t_color = orange
    elif temperature > 27:
        description = "Very Hot"
        t_color = red
    return description

# converts humidity into good/bad description and pen color
def describe_humidity(humidity):
    global h_color
    if humidity < 30:
        description = "Low"
        h_color = red
    elif 30 <= humidity <= 60:
        description = "OK"
        h_color = green
    elif 60 < humidity < 80:
        description = "High"
        h_color = yellow
    elif humidity >= 80:
        description = "Very High"
        h_color = orange        
    return description

# converts pressure into barometer-type description and pen color
def describe_pressure(pressure):
    global p_color
    if pressure < 982:
        description = "Very Low"
        p_color = red
    elif 982 <= pressure < 1004:
        description = "Low"
        p_color = yellow
    elif 1004 <= pressure < 1026:
        description = "OK"
        p_color = green
    elif 1026 <= pressure < 1048:
        description = "High"
        p_color = blue
    elif pressure >= 1048:
        description = "Very High"
        p_color = orange
    return description

# graphs current values fot Temperature, Humididty and Pressure
def draw_graph(temp_value, press_value, humid_value):

    scaled_temp = int((temperature * 5) + 160)
    if scaled_temp <= 9:
        scaled_temp =9
        
    if scaled_temp >= 310:
        scaled_temp =310
    
    describe_temperature(temperature)
    display.set_pen(white)
    display.circle(9, 98, 9)
    display.rectangle(12, 89, 92, 19)
    display.set_pen(blue)
    display.rectangle(106, 89, 53, 19)
    display.set_pen(yellow)
    display.rectangle(161,89,78,19)
    display.set_pen(green)
    display.rectangle(241,89,38,19)
    display.set_pen(orange)
    display.rectangle(281,89,13,19)
    display.set_pen(red)
    display.rectangle(296,89,15,19)
    display.circle(310,98,9)
    display.set_pen(black)
    display.circle((scaled_temp),98,9)
    display.set_pen(white)
    display.circle((scaled_temp),98,5)    
    display.set_pen(t_color)
    display.text(describe_temperature(temperature),150,52,scale=4)    
     
    scaled_humid = int(humidity * (320 / 100))
    if scaled_humid <= 9:
        scaled_humid =9
        
    if scaled_humid >= 310:
        scaled_humid =310    
    
    describe_humidity(humidity)
    display.set_pen(red)
    display.circle(9, 164, 9)
    display.rectangle(12,155,82,19)
    display.set_pen(green)
    display.rectangle(96,155,94,19)
    display.set_pen(yellow)
    display.rectangle(192,155,62,19)
    display.set_pen(orange)
    display.rectangle(256,155,55,19)
    display.circle(310,164,9)
    display.set_pen(black)
    display.circle((scaled_humid),164,9)
    display.set_pen(white)
    display.circle((scaled_humid),164,5)
    display.set_pen(h_color)
    display.text(describe_humidity(humidity),150,117,scale=4)
    
    scaled_press = int((pressuremb - 960) * 3)
    
    if scaled_press <= 9:
        scaled_press =9
        
    if scaled_press >= 310:
        scaled_press =310    
    
    describe_pressure(pressuremb)
    display.set_pen(red)
    display.circle(9, 230, 9)
    display.rectangle(12,221,50,19)
    
    display.set_pen(yellow)
    display.rectangle(64,221,62,19)
    display.set_pen(green)
    display.rectangle(128,221,62,19)
    display.set_pen(blue)
    display.rectangle(192,221,62,19)
    display.set_pen(orange)
    display.rectangle(256,221,52,19)
    display.circle(310, 230, 9)
    display.set_pen(black)
    display.line(127,221,127,240)    
    display.circle((scaled_press),230,9)
    display.set_pen(white)
    display.circle((scaled_press),230,5)
    display.set_pen(p_color)
    display.text(describe_pressure(pressuremb),150,184,scale=4) 
    
def set_pico_time():
    # set the Pico's RTC from the RTC breakout
    RV3028.update_time()
    RTC().datetime([RV3028.get_year(), RV3028.get_month(), RV3028.get_date(),
                    RV3028.get_weekday(), RV3028.get_hours(), RV3028.get_minutes(),
                    RV3028.get_seconds(), 0])
    print(f"Pico RTC set to breakout time: {RV3028.string_date()} {RV3028.string_time()}")
 
#set_pico_time()
    
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

start_time = utime.time()
    
while True:

    time_elapsed = utime.time() - start_time
    hours = rtc.get_hours()
    minutes = rtc.get_minutes()
    month = rtc.get_month()
    date = rtc.get_date()    
     
    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()

        
    temperature, pressure, humidity = bme.read()
    pressuremb = pressure / 100      
     
    temperature = round(temperature)
    humidity = round(humidity)
    pressure = round(pressure)
    
    display.set_pen(white)
    display.text("{:0.0f}°C" .format(temperature), 5, 52, scale=4)
    display.text("{:0.0f} %".format(humidity), 5, 118, scale=4)
    display.text("{:0.0f} mb".format(pressuremb), 5, 184, scale=4)
    
    draw_graph(temperature, pressure, humidity)
    
    
    voltage = vsys.read_u16() * conversion_factor
    percentage = 100 * ((voltage - empty_battery) / (full_battery - empty_battery))
    if percentage > 100:
        percentage = 100
        
    if charging.value() == 1:
        led.set_rgb(0, 0, 0)
    else:
        if percentage >= 50:
            led.set_rgb(0,5,0)
        elif 50 < percentage > 20:   
            led.set_rgb(5,5,0)
        elif percentage <= 20:    
            led.set_rgb(5,0,0)
                    
    if button_a.is_pressed:
        display.set_backlight(0.3)
    
    if button_b.is_pressed:
        if percentage >= 50:
            led.set_rgb(0,5,0)
            display.set_pen(green)
            display.text("Battery",0,9,scale=3)
            display.text("{:0.2f}v".format(voltage),150,9,scale=3)
            display.text("{:0.0f}%".format(percentage),265,9,scale=3)
        elif 50 < percentage > 20:   
            led.set_rgb(5,5,0)
            display.set_pen(yellow)
            display.text("Battery",0,9, scale=3)
            display.text("{:0.2f}v".format(voltage),150,9,scale=3)
            display.text("{:0.0f}%".format(percentage),265,9,scale=3)
        elif percentage <= 20:    
            led.set_rgb(5,0,0)
            display.set_pen(red)
            display.text("Battery",0,9,scale=3)
            display.text("{:0.2f}v".format(voltage),150,9,scale=3)
            display.text("{:0.0f}%".format(percentage),265,9,scale=3)
    else:
        display.set_pen(white)       
        if hours <10:
            display.text(f"{hours:1}:{minutes:02} AM",5,9,scale=3)
        elif 10 <= hours < 12:
            display.text(f"{hours:2}:{minutes:02} AM",0,9,scale=3)
        elif hours == 12:
            display.text(f"{hours:2}:{minutes:02} PM",0,9,scale=3)    
        elif hours >12:
            hours = hours - 12
            if hours <10:
                display.text(f"{hours:1}:{minutes:02} PM",5,9,scale=3)
            elif 10 <= hours < 12:
                display.text(f"{hours:2}:{minutes:02} PM",0,9,scale=3)
            elif hours == 12:
                display.text(f"{hours:2}:{minutes:02} AM",0,9,scale=3)
                
        display.text(f"{describe_month(month)} {date}{describe_date(date)}",130,9,scale=3)         
    
    if button_x.is_pressed:
        display.set_backlight(1.0)
    
    if button_y.is_pressed:
        display.set_backlight(0.5) 
            
    if time_elapsed < 0.2:
        temperature, pressure, humidity = bme.read()
        display.set_pen(black)
        display.clear()
        display.update()
        #utime.sleep(1)
    else:
        display.update()
        utime.sleep(1)
        display.set_pen(black)
        display.clear()    
        #utime.sleep(0.1)
2 Likes

That turned out really well, nice job!

as a note, if you cycle the batteries between 60-80% (ie charge to ~80, run till it drops to ~60) it maximizes their effective lifetime. I personally find it too much of a pain to try to hit 80% charge, but recharging at 60 has noticeably helped extend the life of some of my Lion/Lipo devices.

2 Likes

Thank you Alpha, a snippet of this code helped me to fix a tiny bug on one of my PicoW light analyzers.

Please accept this non redeemable internet medal: 🏅

1 Like

Most of my code starts out as Pimoroni example code. Then I add in bits I’ve seen posted here and there. I never really seem to be finished. I’ll use it for a while and then think, I don’t like that so much now, or I can make that better. Code Hel Gibbons posted had a big impact on how it turned out. @hel

1 Like

One thing I’m finding is, it may be Micro Python, but my code ends up being anything but Micro size wise when I’m done. To do the same thing in Python is usually easier and less code.
Take the above date and time code for example. No strftime in Micro python.

On another side note. I noticed it looked better on my Tufty versus the Display Pack V2. Then I realized the Tufty screen is 2.4 inch versus a 2.0 inch screen on the Display Pack. I hadn’t realized till I went and looked it up. Both are 320 x 240, and minimal editing from one to the other. Just the Display = part, etc. I am liking the Pico Graphics, draw circle, draw rectangle, etc.

Yes, I concur. Though personally at my own, very much a learner skill level. I think I prefer micro python. As you rightly point out, it can at times be micro in name only.

Also liking picographics, now I am more used to using it. It’s a huge improvement. Having one command set across devices makes logical sense too. A few minor tweaks for a different display, and you’re up and running.

Recently ported my mandlebrot drawing script over to use it and it does seem to have improved the visual output. Though compute times for a pico remain unchanged, clearly.

I’ve been pondering some kind of picow cluster. But would have absolutely no idea how to go about it or even code for such a thing. I’ll leave that to the boffins with very long beards to figure out. 😉

I’m self taught, Python wise. Python was what was being used on the Pi side of things so that’s what I went with. Micro Python followed as a result of it being used on the Pico side of things. When I say being used I’m meaning predominantly at the time over other alternatives. To be fair, there are a fair share out there using C. If I was younger I might have had a go at that too. If I’m honest, it’s not very high up on my list of things to do though. ;)

I often find myself getting hung up on how my code looks, or how long it is, but it’s important not to get hung up on that. It works, and nobody else is ever going to see it. With that said, you could use tables and for n in range to get rid of some of those if elif elif elif elif checks, and you could also just you “or” for the part where you check for the last digit of the date to assign st or rd. Those are two easy fixes. For n in range, for example, is a pretty important tool to have.

…but overall, worrying about the length of your code is vanity and the rule to remember is, if it works, it works!

Getting to the “it works”, is goal number 1. =).
Then I do the tweak it part, which usually ends up being:
Break it, fix it, wash rinse and repeat, lol.

I’ll tell you a dirty little secret… except for some of the rarer programming languages, there are really few differences between any of them. The first is always the toughest because you have to learn logic structure, but after that, the hardest thing isn’t learning another language, but remembering which one do and don’t have extra features.