Home Code Pico and SGP40 air quality sensor example in micropython

Pico and SGP40 air quality sensor example in micropython

by shedboy71

In this article we connect an SGP40 air quality sensor to our Raspberry Pi Pico

The SGP40 is Sensirion’s new digital VOC (volatile organic compounds) sensor designed for easy integration into air purifiers or demand-controlled ventilation.

SGP40 is Sensirion’s new digital VOC (volatile organic compounds) sensor designed for easy integration into air treatment devices and air quality monitors.

Based on Sensirion’s CMOSens® Technology, the SGP40 offers a complete sensor system on a single chip and features a digital I²C interface, a temperature-controlled micro-hotplate and a humidity-compensated indoor air quality signal.

In combination with Sensirion’s powerful VOC Algorithm, the sensor signal can be directly used to evaluate indoor air quality

Parts Required

I used a Pico sense hat which has 4 sensors on it, it would be possible to wire up a SGP40 sensor to a Pico board

Name Link
Pico Raspberry Pi Pico Development Board
SGP40

SGP40 SGP30 Air Quality Sensor Digital

Raspberry Pi Pico with Pico Sense HAT Multi Sensor Humidity, Air Quality, Color, Pressure Sensor Sense HAT for Pico with Inbuilt 1.14” LCD Display

In this image you can see a sense hat attached to a Pico

Code Example

I used Thonny and this example is written in Micropython

The first part is a library for the sgp40

You need to upload this to your Raspberry Pi Pico

Go to File > Save as…
Select the Raspberry Pi Pico
Name your file as sgp40.py and press the OK button
And that’s it. The library was uploaded to your board. To make sure that it was uploaded successfully, go to File > Save as… and select the Raspberry Pi Pico device. Your file should be listed there:
After uploading the library to your board, you can use the library in your code by importing the library.

A lot of code to look at but the library is attached to the bottom of the article, this is taken from the github repo for the pico sense hat

from machine import I2C
import utime
import struct
import math
 
class SGP40:
 
    class NotFoundException(Exception):
        pass
 
    class NotSupportedException(Exception):
        pass
 
    class CRCException(Exception):
        pass
 
    MEASUREMENT_RAW = 0x260f
    MEASUREMENT_TEST = 0x280e
    HEATER_OFF = 0x3615
    RESET = 0x0006
 
    GET_SERIAL_ID = 0x3682
    GET_FEATURESET = 0x202f
 
    # Generated using
    # crc_table = []
    # for crc in range(256):
    #     for crc_bit in range(8):
    #         if crc & 0x80:
    #             crc = (crc << 1) ^ CRC8_POLYNOMIAL;
    #         else:
    #             crc = (crc << 1);
    #         crc = crc%256
    #     crc_table.append(crc)
 
    CRC_TABLE = [
        0, 49, 98, 83, 196, 245, 166, 151, 185, 136, 219, 234, 125, 76, 31, 46,
        67, 114, 33, 16, 135, 182, 229, 212, 250, 203, 152, 169, 62, 15, 92, 109,
        134, 183, 228, 213, 66, 115, 32, 17, 63, 14, 93, 108, 251, 202, 153, 168,
        197, 244, 167, 150, 1, 48, 99, 82, 124, 77, 30, 47, 184, 137, 218, 235,
        61, 12, 95, 110, 249, 200, 155, 170, 132, 181, 230, 215, 64, 113, 34, 19,
        126, 79, 28, 45, 186, 139, 216, 233, 199, 246, 165, 148, 3, 50, 97, 80,
        187, 138, 217, 232, 127, 78, 29, 44, 2, 51, 96, 81, 198, 247, 164, 149,
        248, 201, 154, 171, 60, 13, 94, 111, 65, 112, 35, 18, 133, 180, 231, 214,
        122, 75, 24, 41, 190, 143, 220, 237, 195, 242, 161, 144, 7, 54, 101, 84,
        57, 8, 91, 106, 253, 204, 159, 174, 128, 177, 226, 211, 68, 117, 38, 23,
        252, 205, 158, 175, 56, 9, 90, 107, 69, 116, 39, 22, 129, 176, 227, 210,
        191, 142, 221, 236, 123, 74, 25, 40, 6, 55, 100, 85, 194, 243, 160, 145,
        71, 118, 37, 20, 131, 178, 225, 208, 254, 207, 156, 173, 58, 11, 88, 105,
        4, 53, 102, 87, 192, 241, 162, 147, 189, 140, 223, 238, 121, 72, 27, 42,
        193, 240, 163, 146, 5, 52, 103, 86, 120, 73, 26, 43, 188, 141, 222, 239,
        130, 179, 224, 209, 70, 119, 36, 21, 59, 10, 89, 104, 255, 206, 157, 172
        ]
 
    def __init__(self, i2c, addr=0x59):
        self.i2c = i2c
        self.addr = addr
        if not addr in i2c.scan():
            raise self.NotFoundException
 
    def measure_raw(self, humidity=50, temperature=25):
        paramh = struct.pack(">H", math.ceil(humidity * 0xffff / 100))
        crch = self.__crc(paramh[0], paramh[1])
        paramt = struct.pack(">H", math.ceil((temperature + 45) * 0xffff / 175))
        crct = self.__crc(paramt[0], paramt[1])
        data = paramh + bytes([crch]) + paramt + bytes([crct])
        self.i2c.writeto_mem(self.addr, self.MEASUREMENT_RAW, data, addrsize=16)
        utime.sleep_ms(30)
        raw = self.i2c.readfrom(self.addr, 3)
        self.__check_crc(raw)
        return struct.unpack('>H', raw[:2])[0]
 
    def measure_test(self):
        raw = self.__read_bytes(self.MEASUREMENT_TEST, 3, 250000)
        self.__check_crc(raw)
        return struct.unpack('>H', raw[:2])[0]
 
    def reset(self):
        self.__write_command(self.RESET)
 
    def heater_off(self):
        self.__write_command(self.HEATER_OFF)
 
    def get_serial_id(self):
        data = self.__read_bytes(self.GET_SERIAL_ID, 6, 500)
        return data
 
    def __write_command(self, cmd):
        bcmd = struct.pack('>H', cmd)
        self.i2c.writeto(self.addr, bcmd)
 
    def __read_bytes(self, cmd, count, pause):
        self.__write_command(cmd)
        utime.sleep_us(pause)
        return self.i2c.readfrom(self.addr, count)
 
    def __check_crc(self, arr):
        assert (len(arr) == 3)
        if self.__crc(arr[0], arr[1]) != arr[2]:
            raise self.CRCException
 
    def __crc(self, msb, lsb):
        crc = 0xff
        crc ^= msb
        crc = self.CRC_TABLE[crc]
        if lsb is not None:
            crc ^= lsb
            crc = self.CRC_TABLE[crc]
        return crc

You can download from the bottom of this article

Now we need to use these functions

After uploading the library to the Raspberry Pi Pico, copy the following code to the main.py.

This will print the air quality as a raw value into the shell every 5 seconds

rom machine import Pin, I2C
from time import sleep
from sgp40 import SGP40
 
i2c = I2C(1,scl=Pin(7), sda=Pin(6), freq=40000)#all sensor connected through I2C
 
while True:
  air_quality = SGP40(i2c, 0x59)
  Air_quality = air_quality.measure_raw()
  print("Air quality = ",Air_quality)
 
  sleep(5)

 

Output

Here is what I saw in Thonny shell window

>>> %Run -c $EDITOR_CONTENT
Air quality = 26890
Air quality = 26123
Air quality = 25234
Air quality = 25286

Links

sgp40

You may also like

Leave a Comment