Files
Ravi ReddyandClaude Opus 5.5 3b371cdb28 Add VoiceNotes firmware and CDM customer service SQL project
VoiceNotes is an Arduino sketch for the Waveshare ESP32-C6-LCD-0.85 that
records meetings and voice memos to microSD and turns them into notes:

- Records 16 kHz mono WAV (up to 4 h) from the ES7210 dual mics, with a
  boosted preamp and soft-limited digital gain
- Transcribes via an OpenAI-compatible speech-to-text API in ~10 min parts
  cut at quiet points, with retries and resume after failures
- Summarizes the transcript with Claude into meeting notes (decisions,
  action items, topics with timestamps), streamed to and from the card
- Copies the notes to Nextcloud over WebDAV
- Shows recording/processing state on the 0.85" LCD and the LED ring
- Works around the board's SD card failing multi-sector reads

Credentials live in VoiceNotes/secrets.h, which is git-ignored; see
secrets.example.h.

Also adds the Microsoft CDM customer service SQL implementation (DDL,
sample data, reporting queries and docs). Its README is renamed to
CDM_README.md so the repository README stays at the top level.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 22:22:10 +05:30
..

VoiceNotes — voice recorder + AI notes for the Waveshare ESP32-C6-LCD-0.85

Record meetings (up to 4 hours) or voice memos to the microSD card. Then, with one button press, the device transcribes the newest recording and has Claude turn it into meeting notes: decisions, action items and topics. The notes are saved on the card.

Buttons

The board has two usable buttons (BOOT and PLUS). The PWR key is wired to the power-switch chip, so the firmware can't read it. "Button 3" is a long-press:

Action Press What happens
Button 1 – record PLUS click Starts a new recording
Button 2 – stop BOOT click Stops and saves the WAV file
Button 3 – AI notes PLUS hold 1 s Transcribes the latest recording and writes a summary

If you'd rather have a real third button, wire a push-button from a free GPIO to GND and set PIN_BTN_EXTRA in config.h.

Files on the microSD card

/recordings/REC_2026-10-02_14-30-05.wav           16 kHz mono 16-bit WAV
/recordings/last.txt                               remembers the newest recording across reboots
/notes/REC_2026-10-02_14-30-05_transcript.txt      transcript, with [hh:mm:ss] markers every ~10 min
/notes/REC_2026-10-02_14-30-05_transcript.progress only while a transcription is unfinished (used to resume)
/notes/REC_2026-10-02_14-30-05_summary.md          Claude's notes: summary, decisions, action items, topics

The timestamp comes from NTP over Wi-Fi (the ESP32-C6 has no battery-backed clock). If Wi-Fi isn't up when you record, the file is named REC_nodate_xxxxxxxx.wav.

Nextcloud

When the notes are ready, the summary and transcript are also copied to your Nextcloud over WebDAV, into NEXTCLOUD_FOLDER (the folder is created if it doesn't exist). Set it up in secrets.h:

#define NEXTCLOUD_HOST     "nc.example.com"
#define NEXTCLOUD_USER     "you@example.com"
#define NEXTCLOUD_PASSWORD "xxxxx-xxxxx-xxxxx-xxxxx-xxxxx"   // an app password
#define NEXTCLOUD_FOLDER   "secondbrain"

Use an app password, not your login password. Create one in Nextcloud under Settings → Security → Devices & sessions → Create new app password. It works even with two-factor authentication on, and you can revoke it without changing your main password.

If the copy fails, the notes are still on the SD card. Holding PLUS again retries only the Nextcloud step; it doesn't redo the transcription or the summary. To regenerate a summary, delete its _summary.md from the card first.

What the screen and LED ring show

State Screen LED ring
Starting Mic logo, "Connecting Wi-Fi…" Amber spinner
Ready "Ready", time of the last recording Slow blue breathing (amber if Wi-Fi is down)
Recording Blinking ● REC, timer (h:mm:ss after an hour), scrolling level meter Red VU meter that moves with your voice
Saved ✓, date/time, length and size Green flash
Uploading Progress bar, "Part 3 of 12" and % Blue ring fills up with overall progress
Transcribing Cyan spinner, part number Cyan spinning comet
Summarizing Purple spinner, characters received Two purple comets
Saving to Nextcloud Green spinner Green spinning comet
Done ✓ "Notes saved", file name or "Also saved to Nextcloud" Green pulse
Error ✗ and the reason Red blinking
No microSD Red card icon Slow red blink

The status bar shows the clock, the SD card, and Wi-Fi bars.

Setup

  1. Arduino IDE 2.x with the esp32 core 3.x by Espressif (Boards Manager).
  2. Install these libraries from Library Manager: GFX Library for Arduino (moononournation), FastLED, OneButton, U8g2, ArduinoJson (v7).
  3. Copy secrets.example.h to secrets.h and fill in:
    • your Wi-Fi SSID and password, and your timezone,
    • a speech-to-text API key (STT_*). Any OpenAI-compatible /audio/transcriptions endpoint works: OpenAI (whisper-1, gpt-4o-transcribe) or Groq.
    • an Anthropic API key for the summary (ANTHROPIC_API_KEY).
  4. Board settings (Tools menu):
    • Board: ESP32C6 Dev Module
    • USB CDC On Boot: Enabled (so Serial Monitor works over USB-C)
    • Flash Size: 8MB
    • Partition Scheme: 8M with spiffs (3MB APP/1.5MB SPIFFS)
  5. Put a FAT32 microSD card in the slot, then upload.

From the command line:

arduino-cli compile --upload -p /dev/cu.usbmodem* -b esp32:esp32:esp32c6:CDCOnBoot=cdc,FlashSize=8M,PartitionScheme=default_8MB .

Open the Serial Monitor at 115200 baud to see state changes and any API errors. You can also send: p (same as holding PLUS), n (print the latest transcript and summary), d (list recordings), s (SD read test), and u<file name> (choose which recording p and n use).

How it works

File Role
VoiceNotes.ino Setup, buttons, state machine
audio.cpp ES7210 mic codec setup over I2C, I2S capture task, WAV writer
cloud.cpp HTTPS: streams the WAV to speech-to-text, then streams Claude's reply into summary.md
ui.cpp 128×128 screens (drawn off-screen, then pushed to the LCD) and LED ring animations
config.h Pin map and limits
  • Audio: the two onboard mics go through the ES7210 ADC at 16 kHz and are mixed to mono. A high-priority task fills a 2-second RAM buffer, and the main loop writes that buffer to the card. This way a slow SD write can't make the recording skip.
  • Shared SPI bus: the LCD and the microSD use the same SPI pins, so every access takes spiMutex.
  • Long recordings: the WAV header is updated every 10 s, so a power cut mid-meeting still leaves a playable file. Recording stops at 4 hours (MAX_RECORD_SECONDS), or earlier if the card is nearly full.
  • Transcription in parts: speech-to-text APIs accept at most 25 MB per file, so the recording is sent in ~10-minute parts (STT_SEGMENT_SECONDS). Each part is cut at the quietest moment in the 15 s before the target, so no word is split. The end of the previous part's text is sent as a hint, so names and spellings stay consistent. Each part is streamed straight from the card.
  • Resume: each part is retried up to 3 times. If it still fails (for example, Wi-Fi drops), the finished parts are kept, and holding PLUS again continues from where it stopped.
  • SD reads use 512-byte (single-sector) reads. On this board the microSD fails multi-sector reads.
  • Summary: POST /v1/messages to claude-opus-5-5 with streaming. A 2-hour transcript (~100 KB) is too big for the board's RAM, so the request body is streamed from the card, and the reply is written to the card as it arrives. The request sets fallbacks: "default" (beta server-side-fallback-2026-07-01). If the model declines, the API retries on a fallback model instead of failing.
  • If the transcript was saved but the summary step failed, a long-press again reuses the saved transcript and doesn't upload the audio a second time.

Limits and notes

  • Recordings use about 115 MB per hour (16 kHz mono WAV). A 2-hour meeting is ~230 MB.
  • Processing a 2-hour meeting takes roughly 15–25 minutes: 12 parts, each about a minute to upload at ~300 KB/s plus 20–40 s to transcribe, then a minute or two for Claude. The device can't record while it's processing.
  • For multi-hour meetings, run the device from USB power. A small battery won't last.
  • Privacy: your audio goes to the speech-to-text provider, and the transcript goes to Anthropic.
  • TLS certificates are verified with the ESP32 core's built-in CA bundle.

Troubleshooting

Symptom Fix
LED colours wrong (red shows green) Set LED_COLOR_ORDER to GRB in config.h
Recordings are quiet or noisy Change MIC_GAIN_STEP in config.h (10 = 30 dB)
"Microphone init failed" The ES7210 didn't answer at I2C 0x40. Power-cycle the board
STT HTTP 401 / Claude HTTP 401 Check the API keys in secrets.h
File names say nodate Wi-Fi/NTP wasn't ready yet. Wait for the clock in the status bar
Serial warns that audio was dropped Use a faster (Class 10 / U1) microSD card