Tufty with SDC-41 CO2 sensor

I have given it a good try to make my Tufty work with my SDC-41 CO2 sensor but I am having no luck, mainly because I have no programming skills but also because I have no luck.

If there is anyone out there with a working sketch they don’t mind sharing that would be great, barring that are there any talented people out there that want to make a few bucks?

The end goal is to display my name and title, centered and the CO2 level in one of the corners.

What code have you tried so far, examples etc, and did they work?
I don’t have that breakout but I do have a BME280 wired up to my Tufty displaying the temperature, humidity and pressure. I can post it if you want to have a look.

This is my current attempt to get the sensor up:

import time

import pimoroni_i2c
import breakout_scd41
from picographics import PicoGraphics, DISPLAY_TUFTY_2040, PEN_RGB332

display = PicoGraphics(display=DISPLAY_TUFTY_2040, pen_type=PEN_RGB332, rotate=180)

PINS_BREAKOUT_GARDEN = {“sda”: 4, “scl”: 5}
PINS_PICO_EXPLORER = {“sda”: 20, “scl”: 21}

i2c = pimoroni_i2c.PimoroniI2C(**PINS_PICO_EXPLORER)

breakout_scd41.init(i2c)
breakout_scd41.start()

display.set_backlight(1.0)

display.set_pen(background_pen)
display.clear()

while True:
if breakout_scd41.ready():
co2, temperature, humidity = breakout_scd41.measure()
display.set_pen(display.create_pen(0, 0, 0))
display.set_font(‘bitmap8’)
display.text(co2, 75, 10, 320, 5)
time.sleep(1.0)

I suspect (although I can’t double check, with a lack of Tufty in my life!) that you want to be using PINS_BREAKOUT_GARDEN rather than PINS_PICO_EXPLORER.

Or at least, that’s my first thought trying to make sense of the Tufty schematic :-)

Still crashing :(

import time

import pimoroni_i2c
import breakout_scd41
from picographics import PicoGraphics, DISPLAY_TUFTY_2040, PEN_RGB332

display = PicoGraphics(display=DISPLAY_TUFTY_2040, pen_type=PEN_RGB332, rotate=180)

PINS_BREAKOUT_GARDEN = {“sda”: 4, “scl”: 5}

i2c = pimoroni_i2c.PimoroniI2C(**PINS_BREAKOUT_GARDEN)

breakout_scd41.init(i2c)
breakout_scd41.start()

display.set_backlight(1.0)

display.set_pen(background_pen)
display.clear()

while True:
if breakout_scd41.ready():
co2, temperature, humidity = breakout_scd41.measure()
display.set_pen(display.create_pen(0, 0, 0))
display.set_font(‘bitmap8’)
display.text(co2, 75, 10, 320, 5)
time.sleep(1.0)

I know the address of this breakout is 0x62, maybe that is different than the 41? I asked support if this Adafruit SDC40 would work and they said it was the same, but maybe the address is different?

What you say “crashing”, what exactly is happening? Are you getting an error message?

Looking at the SCD41 code, it looks to be expecting 0x62 so that’s not it.

(side note; if you enclose your code in ``` then it should format it nicely, and make it easier for us to make sense of!)

Thanks for the tip.

By crashing I mean the display stops and no numbers are printed.

Well, it looks like you’re not refreshing the display (display.update() after you’ve added your text), for a start.

You probably also want to clear the display before you start writing to it, or it will get messy, but let’s get you displaying something before worrying about that :)

Warning wall of code to follow. This is my Tufty BME280 code.
If you click the </> (Preformatted Text) option its the same as using code tags.
i2c = PimoroniI2C(sda=(4), scl=(5)) is what I use, and it is pins 4 and 5, not 20, 21.

You want to
get your info
display your info
display.update()
time.sleep
display.set_pen(black)
display.clear()

wash,rinse and repeat. ;)

import utime
import machine
import picographics
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")

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

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

# 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_pwr = Pin(27, Pin.OUT)
lux_pwr.value(1) # Turn on power!
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)

t_color = display.create_pen(0,255,0)
h_color = display.create_pen(0,255,0)
p_color = display.create_pen(0,255,0)
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)

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 = "OK"
        t_color = green
    elif 16 < temperature <= 24:
        description = "Warm"
        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 for Temperature, Humidity and Pressure
def draw_graph(temp_value, press_value, humid_value):
    
    scaled_temp = int(temperature * 10)
    if scaled_temp <= 9:
        scaled_temp =9
    if scaled_temp >= 310:
        scaled_temp =310        
    
    describe_temperature(temperature)
    display.set_pen(yellow)
    display.circle(9,98,9)
    display.rectangle(9,89,116,19)
    display.set_pen(green)
    #display.rectangle(127,89,38,19)
    display.rectangle(127,89,38,19)
    display.set_pen(green)
    display.rectangle(165,89,73,19)
    display.set_pen(orange)
    display.rectangle(240,89,28,19)
    display.set_pen(red)
    display.rectangle(270,89,44,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),130,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),130,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),130,184,scale=4) 



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()
    
   
    if button_a.is_pressed:
        print ("Button A pressed")
        utime.sleep(0.2)
        
    if button_b.is_pressed:        
        if percentage >= 50:
            display.set_pen(green)
            display.text("Battery",0,9,scale=3)
            display.text("{:0.2f}v".format(vbat),150,9,scale=3)
            display.text("{:0.0f}%".format(percentage),265,9,scale=3)
        elif 50 > percentage > 20:   
            display.set_pen(yellow)
            display.text("Battery",0,9, scale=3)
            display.text("{:0.2f}v".format(vbat),150,9,scale=3)
            display.text("{:0.0f}%".format(percentage),265,9,scale=3)
        elif percentage <= 20:    
            display.set_pen(red)
            display.text("Battery",0,9,scale=3)
            display.text("{:0.2f}v".format(vbat),150,9,scale=3)
            display.text("{:0.0f}%".format(percentage),265,9,scale=3)
    else:
        display.set_pen(white)       
        if hours == 0:
            display.text(f"{12}:{minutes:02} AM",5,9,scale=3)
        elif 0 < 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_c.is_pressed:
        print ("Button C pressed")
        utime.sleep(0.2)
        
    if button_up.is_pressed:
        display.set_backlight(1.0)
        utime.sleep(0.2)

    if button_down.is_pressed:
        display.set_backlight(0.4)
        utime.sleep(0.2)

    if button_boot.is_pressed:
        print ("Button BOOT/USR pressed")
        utime.sleep(0.2)
        
    #reading = lux.read_u16()
    #print (reading)
         
    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)
    
    vref_en.value(1)
    
    vdd = 1.24 * (65535 / vref_adc.read_u16())
    vbat = (
        (vbat_adc.read_u16() / 65535) * 3 * vdd
    )

    vref_en.value(0)

    # convert the raw ADC read into a voltage, and then a percentage
    percentage = 100 * ((vbat - empty_battery) / (full_battery - empty_battery))
    if percentage > 100:
        percentage = 100
    if percentage < 0:
        percentage = 0

    if time_elapsed < 0.5:
        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(1)