Infineon Team
Published © MIT

Hat Beat: Ultimate New Year's Eve Accessory

Pulse to the music and Enjoy a spectacular fireworks display at midnight!

IntermediateFull instructions provided3 hours231

Things used in this project

Hardware components

S2GO MEMSMIC IM69D MEMS Microphone
Infineon S2GO MEMSMIC IM69D MEMS Microphone
×1
CY8CPROTO-062-4343W
Infineon CY8CPROTO-062-4343W
×1
WS2812B RGB LED Digital Flexibel
×1

Software apps and online services

MicroPython
MicroPython

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
3D Printer (generic)
3D Printer (generic)
Hot glue gun (generic)
Hot glue gun (generic)
Black fabric

Story

Read more

Custom parts and enclosures

3D hat

with changes in the dimensions

Schematics

fritzing doc

Code

nye project

MicroPython
from machine import Pin, PDM_PCM, freq, bitstream, AUDIO_PDM_24_576_000_HZ , RTC
import time
import array
import math
import random
import network
import ntptime
import utime


# Constants
FRAME_SIZE = 1024
SAMPLE_RATE_HZ = 8000
DECIMATION_RATE = 64
AUDIO_SYS_CLOCK_HZ = 24576000
MICROPHONE_GAIN = 6 # Adjusted for lower sensitivity
VOLUME_RATIO = 8 * FRAME_SIZE  # Increased to reduce sensitivity


# LED matrix setup
DIN1 = Pin('P9_1', Pin.OUT, value=0)
led_data = bytearray([0] * (num_leds * 3))
TIMING = [400, 850, 800, 450]
num_leds = 32 * 8

# Initialize audio system clock
freq(AUDIO_SYS_CLOCK_HZ)

# Initialize PDM/PCM
print("PDM_PCM Initialization")
pdm_pcm = PDM_PCM(
    0,
    sck="P10_4",
    data="P10_5",
    sample_rate=SAMPLE_RATE_HZ,
    decimation_rate=DECIMATION_RATE,
    bits=PDM_PCM.BITS_16,
    format=PDM_PCM.MONO_LEFT,
    left_gain=MICROPHONE_GAIN,
    right_gain=MICROPHONE_GAIN,
)
pdm_pcm.init()
print("PDM initialized successfully")

# Function to manually light all LEDs
def manual_light_all(buf):
    bitstream(DIN1, 0, TIMING, buf)

# Function to create color with adjustable brightness
def create_color(red, green, blue, brightness=1.5):
    red = int(red * brightness)
    green = int(green * brightness)
    blue = int(blue * brightness)
    return bytearray([green, red, blue])

# Function to calculate color based on volume
def get_color_by_position(x, y, max_y):
    hue = (x + y) / max_y
    r = int((math.sin(2 * math.pi * hue) + 1) * 127.5)
    g = int((math.sin(2 * math.pi * (hue + 1 / 3)) + 1) * 127.5)
    b = int((math.sin(2 * math.pi * (hue + 2 / 3)) + 1) * 127.5)
    brightness = 0.1 + 0.9 * (y / max_y)
    return create_color(r, g, b, brightness)

# Function to set the color of a specific LED
def set_led_vu(x, y, color):
    if 0 <= x < 32 and 0 <= y < 8:
        if x % 2 == 0:
            index = (x * 8) + y  # Normal order for even columns
        else:
            index = (x * 8) + (7 - y)  # Reverse order for odd columns
        led_data[index * 3: (index + 1) * 3] = color

def set_led_fireworks(x, y, color):
    if 0 <= x < 32 and 0 <= y < 8:
        index = (y * 32) + x
        led_data[index * 3: (index + 1) * 3] = color
        
# Function to update LED matrix based on volume
def update_led_matrix(volume, current_x):
    num_leds_to_light = min(volume // VOLUME_RATIO, 8)
    for y in range(8):
        if y < num_leds_to_light:
            color = get_color_by_position(current_x, y, 8)
            set_led_vu(current_x, y, color)  # Color based on volume level
        else:
            set_led_vu(current_x, y, create_color(0, 0, 0))  # Turn off the LED
    manual_light_all(led_data)
    current_x = (current_x + 1) % 32  # Move to the next column
    return current_x

def trail_effect(x, y, color, delay=0.05):
    for factor in [0.8, 0.6, 0.4, 0.2]:
        set_led_fireworks(x, y, dim_color(color, factor))
        manualLightAll(led_data)
        time.sleep(delay)

def launch_firework(start_y, color, delay=0.05):
    for x in range(16, 21):  # Longer launch sequence
        clear_leds(num_leds)
        set_led_fireworks(x, start_y, color)
        trail_effect(x - 1, start_y, dim_color(color, 0.5), delay)
        manualLightAll(led_data)
        time.sleep(delay)

def star_explosion(y, colors, delay=0.05):
    first_group_coords = [
        (11, y-1), (27, y-1), (26, y-1), (28, y-1),
        (22, y-1), (10, y-1), (12, y-1), (18, y-1),(21,y-1),(19,y-1),(20, y-1)
    ]
    remaining_coords = [
        # Third
        (4, y-1),
        # Eighth
        (4, y),
        # Fourth
        (2, y-1),
        # Second
        (6, y-1),
        # Fifth
        (17, y-1),
        # First
        (23, y-1),
        # Sixth
        (2, y),
        # Seventh
        (6, y)
    ]
    
    yellow_color = create_color(255, 255, 0)
    always_yellow_coords = [(22, y-1), (4, y), (4, y-1), (18, y-1),(26, y-1),(10, y-1),(28, y-1),(12, y-1)]
    
    clear_leds(num_leds)
    manualLightAll(led_data)
    time.sleep(delay)
    
    for color in colors:
        for (sx, sy) in first_group_coords:
            if (sx, sy) in always_yellow_coords:
                set_led_fireworks(sx, sy, yellow_color)
            else:
                if 0 <= sx < 32 and 0 <= sy < 8:
                    set_led_fireworks(sx, sy, color)
        manualLightAll(led_data)
        time.sleep(delay)
    
    for color in colors:
        for (sx, sy) in remaining_coords:
            if  (sx, sy) not in first_group_coords:
                if (sx, sy) in always_yellow_coords:
                    set_led_fireworks(sx, sy, yellow_color)
                else:
                    if 0 <= sx < 32 and 0 <= sy < 8:
                        set_led_fireworks(sx, sy, color)
            
        manualLightAll(led_data)
        time.sleep(delay)
        clear_leds(num_leds)

def shuffle_list(lst):
    """Shuffle the list in place."""
    for i in range(len(lst) - 1, 0, -1):
        j = random.randint(0, i)
        lst[i], lst[j] = lst[j], lst[i]

def explode_firework(colors, delay=0.05):
    positions = list(range(3, 7))  # Positions 4, 5, 6, and 7
    shuffle_list(positions)
    for x in positions:
        launch_firework(x - 1, create_color(255, 255, 255), delay)
        star_explosion(x, colors, delay)
        clear_leds(num_leds)
        
def fireworks_animation(cycles=10, delay=0.05):
    colors = [
        create_color(255, 0, 0), create_color(0, 255, 0), create_color(0, 0, 255),
        create_color(255, 255, 0), create_color(0, 255, 255), create_color(255, 0, 255),
        create_color(255, 165, 0), create_color(255, 20, 147)
    ]

    for _ in range(cycles):
        firework_count = random.randint(2, 5)
        for _ in range(firework_count):
            explode_firework(colors, delay)
        time.sleep(random.uniform(0.2, 1.2))

# Function to connect to Wi-Fi
def network_connect():
    wlan = network.WLAN(network.STA_IF)
    if wlan.isconnected():
        print('[Network] already connected')
        return True

    # Enable and connect to Wi-Fi
    wlan.active(True)
    wlan.connect('XXXX', '123456789')  # Replace with your SSID and Password

    # Wait for the connection to establish
    utime.sleep(5)
    for i in range(0, 100):
        if not wlan.isconnected() and wlan.status() >= 0:
            print("[Network] Waiting to connect..")
            utime.sleep(2)

    # Check connection
    if not wlan.isconnected():
        print("[Network] Connection failed!")
        return False
    else:
        print("Connected to Wi-Fi. Network config:", wlan.ifconfig())
        return True

# Function to synchronize time with NTP server and adjust for the local timezone
def sync_time(timezone_offset=0):
    try:
        print('Synchronizing time with NTP server...')
        ntptime.host = 'pool.ntp.org'  # You can use another NTP server if preferred
        ntptime.settime()
        print('Time synchronized.')
        
        # Adjust time for timezone
        rtc = RTC()
        current_time = list(rtc.datetime())
        current_time[4] = (current_time[4] + timezone_offset) % 24
        rtc.datetime(tuple(current_time))
        print('Time adjusted for timezone.')
        
    except Exception as e:
        print('Failed to synchronize time:', e)

# Function to get the current time
def get_current_time():
    rtc = RTC()
    current_time = rtc.datetime()
    formatted_time = '{:02}:{:02}'.format(current_time[4], current_time[5])
    formatted_date = '{:04}-{:02}-{:02}'.format(current_time[0], current_time[1], current_time[2])
    return formatted_date, formatted_time
# Main loop
def main():
    current_x = 0
    while True:
    # Read audio samples into buffer
        rx_buf = array.array('h', [0] * FRAME_SIZE)
        num = pdm_pcm.readinto(rx_buf)
        if num is None or num == 0:
            print("PDM read failed or no data")
            continue

        volume = 0
        audio_count = num // 2  # Each sample is 2 bytes

    # Calculate the volume by summing the absolute values of all audio samples
        volume = sum(abs(rx_buf[i]) for i in range(audio_count))

    # Update LED matrix based on the calculated volume
        current_x = update_led_matrix(volume, current_x)
   
    if network_connect():
        # Set the timezone offset (e.g., +1 for UTC+1)
        timezone_offset = 1
        sync_time(timezone_offset)
        
        while True:
            date, time = get_current_time()
            # print("Current date:", date, "Current time:", time)
            
            # Check if it is time for the fireworks display 
            if time == '00:00':  # Adjust the time as needed for your specific case
                
                fireworks_animation(cycles=7, delay=0.003)
            
            utime.sleep(1)
     else:
         current_x = update_led_matrix(volume, current_x)
#         print("Cannot proceed without Wi-Fi connection.")
    

    # Reduced delay for quicker updates
    #time.sleep(0.01)
if __name__ == '__main__':

    
    main()

Credits

Infineon Team
93 projects • 140 followers
Thanks to IonEwe.

Comments