-
Notifications
You must be signed in to change notification settings - Fork 0
Firmware Setup
Arduino CLI is required to compile firmware. The build script looks for it in bin/arduino-cli (project-local) first, then falls back to the system PATH.
Install to the project bin/ directory:
cd bin && curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | shOr install system-wide and let the script find it on PATH.
Run once after installing arduino-cli to install the ESP32 core and required libraries (PubSubClient, WebSockets, ArduinoJson):
./scripts/init_arduino.shcp .env.example .envEdit .env and set your values:
| Variable | Description |
|---|---|
WIFI_SSID |
WiFi network name |
WIFI_PASSWORD |
WiFi password |
FIRMWARE_MQTT_HOST |
IP address of your MQTT broker (ESP32-reachable) |
FIRMWARE_MQTT_PORT |
MQTT port (default 1883) |
FIRMWARE_WS_HOST |
IP address for WebSocket audio stream |
FIRMWARE_WS_PORT |
WebSocket port (default 8091) |
MQTT_HOST |
Internal Docker container name (soundspy-mosquitto) |
MQTT_PORT |
MQTT port for Docker services |
DASHBOARD_PORT |
Dashboard HTTP port (default 8091) |
NTFY_PORT |
ntfy push server port (default 8090) |
NTFY_URL |
ntfy URL for the monitor service |
FREQ_THRESHOLD_DBFS |
Alert threshold in dBFS (default -20) |
COOLDOWN_SECONDS |
Minimum seconds between alerts (default 300) |
The ESP32 cannot resolve Docker hostnames, so FIRMWARE_MQTT_HOST and FIRMWARE_WS_HOST must be IP addresses, not hostnames.
The firmware version is hardcoded in node_firmware/node_firmware.ino — it is not set in .env.
The firmware is generic — it contains no node-specific configuration. Node identity is derived at runtime from the ESP32's chip ID. Compile once and flash the same binary to any board.
./scripts/build_firmware.shThe script:
- Reads
.envand injects WiFi credentials and MQTT/WS addresses into thePLACEHOLDER_*tokens in the source - Compiles with arduino-cli for
esp32:esp32:esp32 - Outputs
builds/soundspy_v<version>.binand a symlinkbuilds/soundspy_latest.bin - Also writes
node_firmware/node_firmware.rendered.ino— a secrets-injected copy for manual Arduino IDE flashing
No arguments are needed. The version is read from the .ino source automatically.
Flash to a board for the first time via USB serial:
arduino-cli upload -p /dev/ttyUSB0 --fqbn esp32:esp32:esp32 \
--input-file builds/soundspy_latest.binReplace /dev/ttyUSB0 with the actual serial port (/dev/ttyACM0 on some Linux systems, COMx on Windows). After the first USB flash, all subsequent updates can be done via OTA.
Alternatively, open node_firmware/node_firmware.rendered.ino in the Arduino IDE and use its upload button.
After a node is running and connected, deploy new firmware wirelessly:
./scripts/deploy_ota.sh <chip_id>The chip_id is the 8-character hex string shown in the dashboard node card and on the serial output during boot (e.g., a1b2c3d4).
The script:
- Uploads the firmware binary to the dashboard (
/api/ota/upload) - Triggers the OTA update via the dashboard API (
/api/ota/trigger), which publishes the firmware URL tosoundspy/<chip_id>/controlover MQTT - The ESP32 downloads the firmware (~30 s), flashes it (~10 s), and reboots (~10 s)
To deploy a specific build instead of the latest:
./scripts/deploy_ota.sh a1b2c3d4 builds/soundspy_v1.4.0.binOTA includes automatic rollback: if the new firmware fails to establish MQTT connectivity on boot, the ESP32 bootloader reverts to the previous partition.
You can also trigger OTA from the dashboard UI — navigate to a node card and use the OTA panel.
The hw_experiments branch adds support for a physical button and potentiometer on the breadboard node.
Button (GPIO34)
- One pin → GPIO34
- Other pin → GND
- 10kΩ resistor between GPIO34 and 3.3V (pull-up)
Potentiometer (GPIO35)
- Left pin → GND
- Middle pin (wiper) → GPIO35
- Right pin → 3.3V
- 100nF ceramic cap between GPIO35 and GND (ADC noise filter)
| Action | Effect |
|---|---|
| Short click | Reconnects MQTT |
| Hold 3s | Hard reboot (ESP.restart()) |
50 ms debounce is applied to avoid contact bounce triggering multiple events.
ADC reads map 0–3.3V linearly to 0–10x gain. Changes are published to soundspy/<chip_id>/gain when the delta exceeds 0.5x. The dashboard knob updates automatically via the hw_gain SocketIO event.
Hardware controls run on Core 0 via a FreeRTOS task to avoid blocking the audio loop on Core 1 — see Architecture.
docker logs -f soundspy_dashboard # Dashboard + OTA progress
docker logs -f soundspy_monitor # Alert serviceBoot and log messages from the firmware are also visible in the dashboard's live logs panel, published over MQTT to soundspy/<chip_id>/log and soundspy/<chip_id>/boot.