The code begins by importing the libraries.
import time import board import simpleio import adafruit_sgp30 import displayio import adafruit_imageload from adafruit_emc2101 import EMC2101 from adafruit_funhouse import FunHouse
Next, I2C and the two STEMMA sensors, the SGP30 and EMC2101, are setup.
i2c = board.I2C()
# setup for SGP30 sensor
sgp30 = adafruit_sgp30.Adafruit_SGP30(i2c)
# setup for fan controller
emc = EMC2101(i2c)
print("SGP30 serial #", [hex(i) for i in sgp30.serial])
#SGP30 start-up
sgp30.iaq_init()
sgp30.set_iaq_baseline(0x8973, 0x8AAE)
The adafruit_funhouse library has a FunHouse object that can be used for displayio.
Following that import, the five bitmaps are setup with displayio. There are three background images that will be shown depending on where you are in the code. The remaining two bitmaps are icons to show whether or not you are sending data to Adafruit IO.
# FunHouse setup
funhouse = FunHouse(default_bg=0x0F0F00)
# start-up bitmap
bitmap, palette = adafruit_imageload.load("/scene1_fume.bmp",
bitmap=displayio.Bitmap,
palette=displayio.Palette)
tile_grid = displayio.TileGrid(bitmap, pixel_shader=palette)
# connecting bitmap
bitmap2, palette2 = adafruit_imageload.load("/scene2_fume.bmp",
bitmap=displayio.Bitmap,
palette=displayio.Palette)
grid2 = displayio.TileGrid(bitmap2, pixel_shader=palette2)
# default background
bitmap3, palette3 = adafruit_imageload.load("/scene3_fume.bmp",
bitmap=displayio.Bitmap,
palette=displayio.Palette)
grid3 = displayio.TileGrid(bitmap3, pixel_shader=palette3)
# internet connection icon
bitmap4, palette4 = adafruit_imageload.load("/connect_icon.bmp",
bitmap=displayio.Bitmap,
palette=displayio.Palette)
icon1 = displayio.TileGrid(bitmap4, pixel_shader=palette4, x = 2, y = 2)
# red x icon
bitmap5, palette5 = adafruit_imageload.load("/x_icon.bmp",
bitmap=displayio.Bitmap,
palette=displayio.Palette)
icon2 = displayio.TileGrid(bitmap5, pixel_shader=palette5, x = 2, y = 2)
Following the bitmap imports, a display group is setup and the first bitmap is added to the group. Then two text objects are created, fume_text and fan_text, that will display the data output from the SGP30 and EMC2101 sensors.
# display group
group = displayio.Group()
# adding start-up bitmap to group
group.append(tile_grid)
funhouse.graphics.root_group.append(group)
# text for fume data
fume_text = funhouse.add_text(
text=" ",
text_position=(110, 90),
text_anchor_point=(0.5, 0.5),
text_color=0xf57f20,
text_font="fonts/Arial-Bold-24.pcf",
)
# text for fan RPM data
fan_text = funhouse.add_text(
text=" ",
text_position=(110, 165),
text_anchor_point=(0.5, 0.5),
text_color=0x7fffff,
text_font="fonts/Arial-Bold-24.pcf",
)
# showing graphics
funhouse.display.root_group = funhouse.graphics.root_group
A few state machines and variables are setup for use in the loop. Their functions are commented below.
# state machines run = False # state if main code is running connected = False # checks if connected to wifi start_up = False # state for start-up clock = 0 # time.monotonic() device
Two functions are created to send data to Adafruit IO. send_fume_data() sends data from the SGP30 and send_fan_data() sends data from the ECM2101.
For these functions to work properly, you need to have feeds setup in Adafruit IO called "fumes" and "fan-speed". Be sure to follow the steps on the Adafruit IO Setup page in this guide.
# function for sending fume data to adafruit.io
def send_fume_data(solder_fumes):
funhouse.network.push_to_io("fumes", solder_fumes)
# function for sending fan rpm to adafruit.io
def send_fan_data(fan_rpm):
funhouse.network.push_to_io("fan-speed", fan_rpm)
The loop begins by checking if the main program is running with the run state. If the main program is not running, then the start-up graphic is shown on the FunHouse and you need to press either the middle or bottom button to begin the fume extraction. The buttons determine whether or not you connect to WiFi and send your fume data to Adafruit IO
If you press the down button, the start-up bitmap is removed from group and the main program bitmap is added to group for display. Additionally, the red x icon is also added to group to show that you are not connected to WiFi. Finally, run is set to True so that the fume extraction and data display can begin.
# if you press the down button
if funhouse.peripherals.button_down:
print("run")
# remove start-up bitmap
group.remove(tile_grid)
# add main bitmap
group.append(grid3)
# add red x icon to show not connected to internet
group.append(icon2)
# change state for main program
run = True
If you press the select button (in the middle of the FunHouse's three buttons), the start-up bitmap is removed from group and the "connecting..." bitmap is added to group.
Then, the function funhouse.network.connect() is called. This connects the FunHouse to WiFi.
After a network connection has been established, the start_up state is set to True and clock is reset with time.monotonic().
# if you press the middle button
if funhouse.peripherals.button_sel:
# remove start-up bitmap
group.remove(tile_grid)
# add connecting... bitmap
group.append(grid2)
# connect to the network
funhouse.network.connect()
print("connecting")
# change state for network
connected = True
# start main program
start_up = True
# start time.monotonic()
clock = time.monotonic()
The start-up state exists so that after the FunHouse connects to WiFi, the connecting graphic can be removed from group and replaced with the main graphic. Additionally, the internet icon is added to show that you're sending data to Adafruit IO. Finally, run is set to True.
# after connecting to the internet
if start_up:
# remove connecting bitmap
group.remove(grid2)
# add main bitmap
group.append(grid3)
# add internet icon
group.append(icon1)
# start main program
run = True
# reset start-up state
start_up = False
The main program takes readings from the SGP30 to affect the fan's RPM speed. This is done with the simpleio.map_range() function. You can either use the SGP30's eCO2 readings or TVOC readings. You'll just need to comment and uncomment certain lines to change this.
The data from the SGP30's readings and the fan's RPM are updated for the fume_text and fan_text objects to display on the screen.
# fumes variable for reading from SGP30
# comment out either TVOC or eCO2 depending on data preference
fumes = sgp30.TVOC
# fumes = sgp30.eCO2
# mapping fumes data to fan RPM
# value for TVOC
mapped_val = simpleio.map_range(fumes, 10, 1000, 10, 100)
# value for eCO2
# mapped_val = simpleio.map_range(fumes, 400, 2500, 10, 100)
# adding fume text
# PPB is for TVOC, PPM is for eCO2
funhouse.set_text("%d PPB" % fumes, fume_text)
# funhouse.set_text("%d PPM" % fumes, fume_text)
# adding fan's RPM text
funhouse.set_text("%d%s" % (mapped_val, "%"), fan_text)
# printing fan's data to the REPL
print("fan = ", mapped_val)
# setting fan's RPM
emc.manual_fan_speed = int(mapped_val)
Every fifteen seconds, the data from the SGP30 and EMC2101 are sent to feeds on Adafruit IO. After the data is sent, clock is reset with time.monotonic().
# if you're connected to wifi and 15 seconds has passed
if connected and ((clock + 15) < time.monotonic()):
# send fume data to adafruit.io
send_fume_data(fumes)
# send fan RPM to adafruit.io
send_fan_data(mapped_val)
# REPL printout
print("data sent")
# reset clock
clock = time.monotonic()
If you decide after booting up the FunHouse that you want to connect or disconnect from WiFi, you can press the up button on the FunHouse next to the icon in the top left corner of the screen.
The connection is affected by changing the connected state. The icon also changes to show the connection status visually.
# if you're connected to wifi and you press the up button
if connected and funhouse.peripherals.button_up:
# the internet icon is removed
group.remove(icon1)
# the red x icon is added
group.append(icon2)
# reset connected state - no longer sending data to adafruit.io
connected = False
# REPL printout
print("disconnected")
# 1 second delay
time.sleep(1)
# if you're NOT connected to wifi and you press the up button
if not connected and funhouse.peripherals.button_up:
# the red x icon is removed
group.remove(icon2)
# the internet icon is added
group.append(icon1)
# the connection state is true - start sending data to adafruit.io
connected = True
# REPL printout
print("connected")
# 1 second delay
time.sleep(1)
Page last edited July 28, 2025
Text editor powered by tinymce.