element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Sci-Pi Design Challenge
  • Challenges & Projects
  • Design Challenges
  • Sci-Pi Design Challenge
  • More
  • Cancel
Sci-Pi Design Challenge
Blog Measuring air quality with Raspberry Pi #6 - Summary
  • Blog
  • Forum
  • Documents
  • Leaderboard
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Sci-Pi Design Challenge to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: deimosmuc
  • Date Created: 23 Jun 2023 6:59 PM Date Created
  • Views 1520 views
  • Likes 5 likes
  • Comments 5 comments
  • eagle
  • python
  • pcb
  • raspberry pi
  • sps30
  • schematic
  • sci-pi design challenge
Related
Recommended

Measuring air quality with Raspberry Pi #6 - Summary

deimosmuc
deimosmuc
23 Jun 2023

Project Summary

In my contest project, I documented the process of measuring air quality using Raspberry Pi and the SPS30 particle matter sensor. I shared my journey through a series of blog posts.

The first post, "Introduction," gives an overview of the project and its objectives. It explains the importance of monitoring air quality and introduces the Raspberry Pi as the central component of the measurement system. Link

In the second post, "Sensor Sensirion SPS30," I dive into the details of the Sensirion SPS30 sensor, which I used to measure various pollutants. I discuss its features, wiring, and communication with the Raspberry Pi. Link

The third post, "PCB," focuses on the design and fabrication of a custom PCB (Printed Circuit Board) for the project. I explain the PCB layout, components, and connections, highlighting the importance of a well-designed board for accurate measurements. Link

Moving on to the fourth post, "First Measurements," I share the exciting results of the initial measurements conducted using the Raspberry Pi and SPS30 sensor. I discuss the data collection process and present visualizations of the recorded air quality parameters. Link

Lastly, in the fifth post, "Further Measurements," I provide an update on the project, showcasing additional measurements and analyses. I discuss the challenges faced during the project and propose potential solutions for improving air quality based on the collected data. Link

Shopping list

here is a little shopping list, for the items you will need in this project:

  • Raspberry Pi 3B+ or later ~60€
  • SPS30 Particulate Matter (PM) sensor plus cable~49€
  • SPS30 Interface HAT PCB (with nice purple colour) ~5€
  • SMD connector parts ~5€
  • Enclosure 10-20€
  • optional BME680 Bosch Sensor (Adafruit Board) ~20€

Schematic and PCB

The schematic and PCB were designed in a free version of Eagle and manufactured by JLCPCB. 

The schematic/PCB does not only connect the SPS30 Sensor to the Raspberry PI via the HAT connector, but I have also added QWIC connectors, so you can add your favourite Adafruit or Sparkfun board to the Raspi. In my case, I have added a BME680 Adafruit board, in order to get even more environmental data like temperature and humidity and air pressure. 

image

4466.SPS30_QWIIC_HAT.zip

My hardware setup

So my hardware setup looks like this:

Hardware setup

And as promised you can finally see the nice purple colour of the SPS30 Interface HAT:

Hardware Setup

Python Code

I have used the Thonny IDE on the Raspberry PI. It is a very nice and helpful tool to develop and run the Python Code directly on Raspi.

Thonny IDE

external libraries:

in order not to develop the wheel myself, if have used the following external libs that need to be installed before starting the code:

SPS30 library from: https://github.com/dvsu/sps30

thingspeak library from: https://thingspeak.readthedocs.io/en/latest/ 

<optional> BME680  library from: https://github.com/pimoroni/bme680-python

here is the full code:

import sys
import json
from time import sleep
from sps30 import SPS30

import bme680

import thingspeak

#adjust these values here 
channel_id = 123456 # PUT CHANNEL ID HERE
mywrite_key  = 'keykeykey' # PUT YOUR WRITE KEY HERE
myread_key   = 'keykeykeykey' # PUT YOUR READ KEY HERE
 

if __name__ == "__main__":
    
    channel = thingspeak.Channel(id=channel_id, api_key=mywrite_key)
    
    #BME680 Sensor
    try:
        sensor = bme680.BME680(bme680.I2C_ADDR_PRIMARY)
    except (RuntimeError, IOError):
        sensor = bme680.BME680(bme680.I2C_ADDR_SECONDARY)
    
        
    # These calibration data can safely be commented
    # out, if desired.

    print('Calibration data:')
    for name in dir(sensor.calibration_data):

        if not name.startswith('_'):
            value = getattr(sensor.calibration_data, name)

            if isinstance(value, int):
                print('{}: {}'.format(name, value))

    
    # These oversampling settings can be tweaked to
    # change the balance between accuracy and noise in
    # the data.
   
    sensor.set_humidity_oversample(bme680.OS_2X)
    sensor.set_pressure_oversample(bme680.OS_4X)
    sensor.set_temperature_oversample(bme680.OS_8X)
    sensor.set_filter(bme680.FILTER_SIZE_3)
    sensor.set_gas_status(bme680.ENABLE_GAS_MEAS)
    
        
    print('\n\nInitial reading:')
    for name in dir(sensor.data):
        value = getattr(sensor.data, name)

        if not name.startswith('_'):
            print('{}: {}'.format(name, value))

    sensor.set_gas_heater_temperature(320)
    sensor.set_gas_heater_duration(150)
    sensor.select_gas_heater_profile(0)
    
    # Up to 10 heater profiles can be configured, each
    # with their own temperature and duration.
    # sensor.set_gas_heater_profile(200, 150, nb_profile=1)
    # sensor.select_gas_heater_profile(1)
    
    
    #SPS30 Sensor
    pm_sensor = SPS30()
    try:
        print(f"Firmware version: {pm_sensor.firmware_version()}")
        print(f"Product type: {pm_sensor.product_type()}")
        print(f"Serial number: {pm_sensor.serial_number()}")
        print(f"Status register: {pm_sensor.read_status_register()}")
        print(f"Auto cleaning interval: {pm_sensor.read_auto_cleaning_interval()}s")
        #print(f"Set auto cleaning interval: {pm_sensor.write_auto_cleaning_interval_days(2)}s")
        pm_sensor.start_measurement()
    
    except:
        print("Exception Initialisierung")

    while True:
        try:
            #SPS30
            SPS30_werte=pm_sensor.get_measurement()
            
            print(json.dumps(pm_sensor.get_measurement(), indent=2))
            
            #BME680
            if sensor.get_sensor_data():
                output = '{0:.2f} C,{1:.2f} hPa,{2:.2f} %RH'.format(
                    sensor.data.temperature,
                    sensor.data.pressure,
                    sensor.data.humidity)

                if sensor.data.heat_stable:
                    print('{0},{1} Ohms'.format(
                        output,
                        sensor.data.gas_resistance))

                else:
                    print(output)
            
            #{'sensor_data': {'mass_density': {'pm1.0': 0.345, 'pm2.5': 0.379, 'pm4.0': 0.391, 'pm10': 0.397}, 'particle_count': {'pm0.5': 2.347, 'pm1.0': 2.726, 'pm2.5': 2.748, 'pm4.0': 2.752, 'pm10': 2.754}, 'particle_size': 0.479, 'mass_density_unit': 'ug/m3', 'particle_count_unit': '#/cm3', 'particle_size_unit': 'um'}, 'timestamp': 1678649674}
            
            
            if SPS30_werte: #we check if the dict is filled, this is not the case at the very beginning
                
                print(SPS30_werte['sensor_data']['mass_density']['pm1.0'])
                
                try:
                   response = channel.update({'field1': sensor.data.temperature, 'field2': sensor.data.pressure, 'field3': sensor.data.humidity, 'field4': SPS30_werte['sensor_data']['mass_density']['pm1.0'], 'field5': SPS30_werte['sensor_data']['mass_density']['pm2.5'], 'field6': SPS30_werte['sensor_data']['mass_density']['pm4.0'], 'field7': SPS30_werte['sensor_data']['mass_density']['pm10'], 'field8': SPS30_werte['sensor_data']['particle_count']['pm2.5']})
                except:
                   print("Error while communicating with thingspeak.com")
            sleep(4)
        
        

        except KeyboardInterrupt:
            print("Stopping measurement...")
            pm_sensor.stop_measurement()
            sys.exit()
            
        
            

So what next:

Next, I will finish the enclosure for the hardware and I'll be taking more measurements this coming winter when my beloved neighbours get their wood stoves glowing and the outside air stinking again. 

Another cool follow-up project would be integrating the air quality measurement system with a Switchbot system would allow for dynamic control of my existing (not smart and sensor-free) air purifier.

  • Sign in to reply
Parents
  • DAB
    DAB over 2 years ago

    Nice finish, overall I would say you did a good job testing the sensor.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
Comment
  • DAB
    DAB over 2 years ago

    Nice finish, overall I would say you did a good job testing the sensor.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
Children
  • deimosmuc
    deimosmuc over 2 years ago in reply to DAB

    thank you :), I was glad I also had the BME680 sensor attached, so I could see that the PM sensor is sensitive to humidity. 

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube