Shhh! The Baby’s Sleeping: Our Fun DIY Adventure in Noise Monitoring
Okay, folks, gather around for a story — it’s adventure time!
You know how our little bundles of joy, our babies, are the superheroes of sleep? They have the superpower to sleep through anything, and yet another superpower to wake up to the quietest sound! So, this adventure is all about how I created a ‘Silence Guardian’ for my baby’s room using some cool tech.
Once Upon a Tech Time…
Our quest begins with the mighty Raspberry Pi Pico W, a microcontroller with WiFi superpowers, and a friendly sidekick — a low-cost LM393 sound detection module. This dynamic duo teamed up to listen for any sounds that might disturb our sleeping superhero.
To the Cloud!
But what’s a superhero story without some magic? That’s where Initial State comes in. It’s a magical realm (data streaming service) where the Pico sends signals (sound detection events) if it hears a loud noise. Initial State keeps an eye (or ear!) on these signals and sends a message in a flash (text notification) if it detects a loud event.
Casting Spells with MicroPython
Every magic trick needs a spell, right? Our spell is written in MicroPython, a wizard-friendly version of Python 3 that’s perfect for casting spells (coding) on microcontrollers.
The Adventure Unfolds
We embarked on our quest with great enthusiasm, but every good adventure has its challenges. We first tried using a magic tool called Direct Memory Access (DMA), but it proved to be a tricky beast. So, we took a different path, treating our LM393 sidekick as a simple ‘yes/no’ sensor (high/low signal) and monitoring small ‘rolling’ windows of time to detect noises.
The Art of Listening
We spent some time fine-tuning our noise detection. It was like teaching our Pico to understand the difference between a whisper and a shout. I used a magical device called an oscilloscope that lets me see the sounds the Pico was hearing, making it easier to adjust our noise detection. But even without an oscilloscope, you can teach your Pico to listen — just use print statements in your spell (code) to understand what it’s hearing.
And They Lived Quietly Ever After
Our DIY adventure turned out to be a great success! We’ve become the guardians of silence for our little superhero’s dreams. And the best part? If we’re too loud, our phones get a text, reminding us to use our inside voices.
So, fellow adventurers, are you ready to embark on your own quest for quiet? Grab your gear, cast your spells, and let’s give our little superheroes the peaceful dreams they deserve!
Pictures
We decided to attach our sensor right next to the baby monitor camera, with the mic sensor facing the door. Also, we highly recommend befriending someone with a 3-d printer to create a nice little case for your project. And of-course, good wire management for the project will teach your baby good organization skills 😜
Things you’ll need
- Pico W with MicroPython image
- Microphone Sensor (link)
- Micro USB cable with wall adapter to power up your project. (link)
- Soldering Station is a nice to have
Wire everything together as below
Optional: Being able to see electrical signals on a scope is extremely helpful in understanding what your sensor is hearing and what your microcontroller is seeing. The pink signal is what my pico received when I made some noises. The blue signal is the 3V out of the pico.
Code
Here is my code if you want to try this out. I’ve over-saturated with comments to help newbies like me get started easily.
# Import necessary libraries
import machine
import utime
import network
import urequests as requests
import ujson
import secret as s
import gc
# Define the pin connected to the microphone sensor's output
# IDK why and makese no sense but PULL_UP works better than PULL_DOWN. Magic!
mic_sensor_pin = machine.Pin(0, machine.Pin.IN, machine.Pin.PULL_UP)
# Set the duration of the rolling window in seconds
rolling_window_duration = 1
# Set the number of samples to collect per second.
# The Pico struggles with higher sample rate
samples_per_second = 500
# Set the number of consecutive windows to consider for a loud event
consecutive_windows_threshold = 3
# Initialize an empty list to store the rolling window data
rolling_window_buffer = []
# Initialize a variable to keep track of the number of sent messages
sent_count = 0
# Function to connect to WiFi
def connect_wifi(ssid, password):
# Initialize the WiFi interface
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
try:
# Check if the device is already connected to WiFi
if not wlan.isconnected():
print('Connecting to WiFi...')
wlan.connect(ssid, password)
# Wait until the device is connected to WiFi
while not wlan.isconnected():
pass
print('Connected to WiFi with IP address', wlan.ifconfig()[0])
except:
print('Failed to connect to WiFi!')
# Function to send data to the API
def send_data(label, value):
# Perform garbage collection to free up memory
# As Pico was running out of resources here.
gc.collect()
# Prepare the data to be sent
values = {"events": [{"key": label, "value": value}]}
try:
# Send a POST request to the API
response = requests.post(s.url, headers=s.headers, json=values)
# Close the connection after the request is completed
response.close()
except Exception as e:
print("Failed to send data:", e)
# Connect to WiFi
connect_wifi(s.ssid, s.password)
utime.sleep(2)
# Start the main loop
# The logic is simple: monitor a window of time, count high signals (noises),
# If its more than the threshold, send event to Initial State
while True:
# Calculate the rolling window size in number of samples
rolling_window_size = int(rolling_window_duration * samples_per_second)
# Collect the current state of the microphone sensor
rolling_window = [mic_sensor_pin.value() for _ in range(rolling_window_size)]
# Count the number of loud sound events in the rolling window
loud_sound_count = sum(1 for state in rolling_window if state == 1)
# Check if the number of loud sounds is above the threshold
if loud_sound_count > (rolling_window_size * 0.1):
# Add a loud sound event to the rolling window buffer
rolling_window_buffer.append(1)
# Check if the number of consecutive loud sound events is above the threshold
if len(rolling_window_buffer) >= consecutive_windows_threshold:
# Increase the sent count
sent_count += 1
# Clear the rolling window buffer
rolling_window_buffer.clear()
# Send data to the API indicating a loud sound event
# Had to include sleep since pico wasn't fast enough.
send_data("Loud Noise", 1)
utime.sleep(3)
send_data("Loud Noise", 0) # to make my dashboard look nice
utime.sleep(3)
else:
# Clear the rolling window buffer if no loud sound was detected
rolling_window_buffer.clear()
# Sleep for a while to adjust the sample rate
utime.sleep_ms(10000 // samples_per_second)
Here is the secrets.py file with all the API and wifi stuff:
#initial State stuff
url = 'https://groker.init.st/api/events'
headers = {
'Content-Type': 'application/json',
'X-IS-AccessKey': 'Your API Key',
'X-IS-BucketKey': 'Your Bucket ID',
'Accept-Version': '~0'}
#Wifi Stuff
ssid = "Your WIFI Name"
password = "Your Wifi password"
Bonus use case, Use at your own risk
If your spouse’s work-from-home early morning ‘loud’ meetings wake you up, place one of these sensors on their desk! Works as a great sleep guardian for you too 😜