Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Socket server: Unknown command in packed received: [some number] #666

Open
jmadotgg opened this issue Nov 9, 2024 · 0 comments
Open

Socket server: Unknown command in packed received: [some number] #666

jmadotgg opened this issue Nov 9, 2024 · 0 comments

Comments

@jmadotgg
Copy link

jmadotgg commented Nov 9, 2024

Bug report

Problem

I get the error "Unknown command in packet received: 31202" when running the ledstrip example with the python audioserver.py sample script. After that the connection is closing and the server as well as the python client keep retrying to establish a connectionn. I've looked into the socket server and the command16 variable is only supposed to have the values 3 or 4, is that right?
Steps

  1. Install python audioserver.py dependencies, setup correctly with esp32 ip.
  2. compile ledstrip example with correct ssid and password in secrets.h
  3. Upload example and run python script

Example
Is something here not configured correctly?

#!/usr/bin/python
##+--------------------------------------------------------------------------
##
## audioserver - (c) 2023 Dave Plummer.  All Rights Reserved.
##
## File:        audioserver.py - Pushes Audio FFT data to NightDriverStrip
##
## Description:
##
##    Samples the system audio, splits it into bands using an FFT, and then
##    sends is over WiFi to a NightDriverStrip instance
##
## History:     Feb-20-2023     davepl      Created
##
##---------------------------------------------------------------------------

import pyaudio
import numpy as np
import socket
import struct
import time
import sys

# NightDriver ESP32 wifi address - update to your ESP32 WiFi

client = '192.168.178.72'        

# Set up audio input stream. 512@24000 gives a nice framerate.  And 512
# is what I run on the ESP32 if connected via hardware mic, so at least it matches

chunk_size   = 512
sample_rate  = 44100
max_freq     = 20000
num_bands    = 12

# Correction I apply to get a mostly linear response across the bands.  

if num_bands == 16:
    band_scalars = [ 0.35, 0.20, 0.125, 0.1, 0.5, 1.2, 1.7, 2.0, 2.1, 2.75, 2.0, 8.0, 8.0, 8.0, 8.0, 8.0 ]
else:
    if num_bands == 12:
        band_scalars = [ 1.0, 1.0, 1.0, 1.0, 0.01, 0.01, 0.01, 0.1, 0.1, 0.1, 0.1, 1.0 ]

# Open the audio stream.  I'm reading from the mic here because I could not find a system independent
# way to read from the default output device, which would normally require a loopback instance be 
# installed and for simplicity sake, I don't want that.

p = pyaudio.PyAudio()

#
# Set up FFT parameters:
#

fft_size = 2**12  # Choose the size of the FFT (power of 2 for efficiency)

# Calculate the frequencies corresponding to each FFT bin.  

freqs = np.fft.rfftfreq(fft_size, d=1.0/sample_rate)  

# Divide the frequency range into frequency bands of equal logrithmic width
# `20` is the minimum frequency of human hearing, `max_freq` is the maximum frequency of interest, 
# and `num_bands` is the desired number of frequency bands.  

bands = np.logspace(np.log10(20), np.log10(max_freq), num_bands+1).astype(int)  

# Compute the width of each frequency band.  This returns the detla between band (n, n+1)) for each band

band_widths = np.diff(bands)  # Take the difference between adjacent frequency band limits

# The socket we will open to the ESP32 to send our band data to

print("Connect to " + client + "...")

sock = None

stream = p.open(format=pyaudio.paFloat32, channels=1, rate=sample_rate, input=True, frames_per_buffer=chunk_size)

# Loop to continuously sample audio and compute spectrum analyzer bands
while True:

    # Connect to the socket we will be sending to if its not already connected
    if sock == None:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        address = (client, 49152)
        sock.connect(address)
        sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
        sock.setblocking(True);

    # Read the raw audio data.  We ignore overflow exceptions from not accepting every bit, it's ok if
    # miss a few in betweeen samples
    audio_data = np.frombuffer(stream.read(chunk_size, exception_on_overflow=False), dtype=np.float32)
    
    # Compute the FFT to put the samples into frequency
    fft_data = np.abs(np.fft.rfft(audio_data, n=fft_size))

    # Compute band values
    band_values = []
    for i in range(len(bands)-1):                                       # BUGBUG RANGE stops one before
        band_start = np.searchsorted(freqs, bands[i])
        band_stop = np.searchsorted(freqs, bands[i+1])
        band_value = np.median(fft_data[band_start:band_stop])
        band_values.append(band_value)
    
    band_values = np.multiply(band_values, band_scalars)

    # Scale band values to [0, 1]
    band_values = np.clip(band_values, 0.000001, None)                  # Avoid div by zero
    max_band_value = np.max(band_values) + 0.000001;                    # Avoid zero maximumum
    if (max_band_value > 1):
        scaled_values = np.divide(band_values, max_band_value)
    else:
        scaled_values = band_values
        
    # Convert scaled values to ASCII bargraph
    bargraphs = []
    for scaled_value in scaled_values:
        asterisks = "*" * int(round(scaled_value * 8))
        bargraph = f"{asterisks:<8}"
        bargraphs.append(bargraph)

    # Print ASCII bargraphs
    #breakpoint()
    print(bargraphs)
    sys.stdout.write('*')

    # Compose and send the PEAKDATA packet to be sent to the ESP32 NightDriverStrip instance

    packed_data = struct.pack('f' * len(scaled_values), *scaled_values)
    command = 4
    length32 = 4 * num_bands
    seconds = int(time.time())
    micros  = time.perf_counter() - seconds
    
    header1 = (command).to_bytes(2, byteorder='little')             # Offset 0, command16
    header2 = (num_bands).to_bytes(2, byteorder='little')           # Offset 2, num_bands
    header3 = (length32).to_bytes(4, byteorder='little')            # Offset 4, length32 
    header4 = (seconds).to_bytes(8, byteorder='little')             # Offset 8, seconds
    header5 = struct.pack('d', micros)                              # Offset 16, micros
   
    complete_packet = header1 + header2 + header3 + header4 + header5 + packed_data

    try:
        sock.send(complete_packet)
    except socket.error as e:
        #breakpoint()
        print("Socket error!");
        sock.close()
        sock = None
    
    time.sleep(0.015);

sock.close()

The globals.h section for the ledstrip demo:

#elif LEDSTRIP

    // The LED strips I use for Christmas lights under my eaves

    #ifndef PROJECT_NAME
    #define PROJECT_NAME            "Ledstrip"
    #endif

    #ifndef ENABLE_WEBSERVER
    #define ENABLE_WEBSERVER            0   // Turn on the internal webserver
    #endif

    #define ENABLE_WIFI                 1   // Connect to WiFi
    #define INCOMING_WIFI_ENABLED       1   // Accepting incoming color data and commands

    #define WAIT_FOR_WIFI               1   // Hold in setup until we have WiFi - for strips without effects
    #define TIME_BEFORE_LOCAL           5   // How many seconds before the lamp times out and shows local content
    #define COLORDATA_SERVER_ENABLED    1   // Also provides a response packet
    #define NUM_CHANNELS    1
    #define MATRIX_WIDTH    (1*144)     // My maximum run, and about all you can do at 30fps
    #define MATRIX_HEIGHT   1
    #define NUM_LEDS        (MATRIX_WIDTH * MATRIX_HEIGHT)
    #define ENABLE_REMOTE   0                     // IR Remote Control
    #define ENABLE_AUDIO    0                     // Listen for audio from the microphone and process it

    #ifndef LED_PIN0
        #define LED_PIN0        5
    #endif

    #define DEFAULT_EFFECT_INTERVAL     (1000*20)

    #define RING_SIZE_0 1
    #define RING_SIZE_1 2
    #define RING_SIZE_2 4
    #define RING_SIZE_3 8
    #define RING_SIZE_4 16

Notes
I have connected to led strips to port 5 of my esp32.

Thank you very much for your help! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant