Skip to content

ni9aii/fresnel-beacon

Repository files navigation

Fresnel Beacon

A desktop lighthouse lamp: ESP32-S3 drives an 8×8 WS2812B LED matrix mounted inside a Fresnel lens to simulate a rotating lighthouse beam — no moving parts.

Concept

A real lighthouse rotates its optics around a fixed light source. This project inverts that: the lens is static, and LEDs fire in sequence to synthesize the sweeping beam effect electronically.

Hardware

Component Part Notes
MCU + LED panel Waveshare ESP32-S3-Matrix ESP32-S3 + 8×8 WS2812B, USB-C
Optics Fresnel lens Mounted over the LED matrix
Power USB-C 5V Via onboard connector
Enclosure TBD Lighthouse-shaped, 3D printed

Firmware Stack

  • Framework: ESP-IDF v5.3 (FreeRTOS)
  • LED driver: RMT peripheral → WS2812B
  • Watchdog: esp_task_wdt (5 s timeout)
  • Language: C

Features

  • Core beacon animation (rotating beam sweep with quadratic falloff)
  • 4 animation modes — BEACON, STROBE, AMBIENT, OFF
  • Input validation — speed, brightness, color, mode clamping with warnings
  • Error handling — esp_err_t propagation, cleanup on failure
  • Unit tests (beacon math, LED driver logic)
  • CI pipeline (build, static analysis, Wokwi simulation)
  • Task watchdog and stack monitoring
  • Phase 2: Runtime configuration via REST API + Web UI
    • IPC queue for thread-safe config updates
    • NVS persistent storage (speed, mode, brightness, color)
    • WiFi STA + AP fallback (AP password derived from MAC)
    • HTTP server with embedded Web UI
  • Configurable rotation speed (0.5-20 sec per rotation)
  • Brightness control (0.0-1.0)
  • Color picker with presets and live preview
  • HTTP Basic Auth for REST API
  • OTA updates (HTTPS-only)
  • mDNS service discovery (fresnel-beacon.local)
  • Renderer abstraction (mock + LED renderers)

Firmware Architecture

app_main
├── config_manager_init()          — load config from NVS
├── wifi_manager_init()            — STA + AP fallback
├── http_server_start()            — REST API + Web UI
├── mdns_service_init()            — mDNS advertisement
└── beacon_animation_task          — main animation loop
    ├── Per-frame: clear matrix, compute beam, set pixels, flush
    ├── process_ipc_commands()     — apply config updates from queue
    ├── esp_task_wdt: subscribe + periodic reset
    └── Stack high-water mark logging (every 30 s)

Project Structure

fresnel-beacon/
├── main/
│   ├── main.c                    — app_main: init all subsystems
│   ├── credentials.h.example     — WiFi credentials template
│   └── CMakeLists.txt
├── components/
│   ├── led_driver/               — RMT-based WS2812B driver
│   │   ├── led_driver.c
│   │   └── include/led_driver.h
│   ├── beacon_animation/         — Animation mode state machine
│   │   ├── beacon_animation.c
│   │   └── include/
│   │       ├── beacon_animation.h
│   │       └── beacon_math.h     — Inline math (pixel_index, angle_diff)
│   ├── config_manager/           — Runtime config + NVS persistence
│   │   ├── config_manager.c
│   │   └── include/config_manager.h
│   ├── ipc/                      — Inter-process communication queue
│   │   ├── ipc.c
│   │   └── include/ipc.h
│   ├── http_server/              — REST API + embedded Web UI
│   │   ├── http_server.c
│   │   └── include/http_server.h
│   ├── wifi_manager/             — WiFi STA/AP + event handling
│   │   ├── wifi_manager.c
│   │   └── include/wifi_manager.h
│   ├── renderer/                 — Renderer abstraction (vtable)
│   │   ├── renderer.c
│   │   └── include/renderer.h
│   ├── auth/                     — HTTP Basic Auth
│   │   ├── auth.c
│   │   └── include/auth.h
│   ├── ota_manager/              — OTA updates (HTTPS)
│   │   ├── ota_manager.c
│   │   └── include/ota_manager.h
│   └── mdns_service/             — mDNS service discovery
│       ├── mdns_service.c
│       └── include/mdns_service.h
├── test/
│   ├── test_beacon_math.c        — Host unit tests (angle math, pixel mapping)
│   ├── test_led_driver.c         — Host unit tests (GRB order, bounds)
│   ├── test_config_manager.c     — ESP-IDF Unity tests (NVS roundtrip)
│   ├── test_ipc.c                — ESP-IDF Unity tests (queue ops)
│   ├── test_esp_http_server.c    — ESP-IDF compile-check
│   ├── test_esp_led_driver.c     — ESP-IDF compile-check
│   └── test_esp_wifi_manager.c   — ESP-IDF compile-check
├── CMakeLists.txt
├── sdkconfig.defaults
├── diagram.json                  — Wokwi simulation layout
├── wokwi.toml                    — Wokwi config
├── scenario.yaml                 — Wokwi test scenario
├── .clang-format                 — Code style (LLVM, 4-space, 100 col)
├── .clang-tidy                   — Static analysis config
└── .github/workflows/
    ├── ci.yml                    — Test, analyze, build + simulate
    └── release.yml               — Build + publish on v* tags

REST API

Method Endpoint Auth Description
GET /api/status No Current config + WiFi status (JSON)
POST /api/config Yes Update config (speed, mode, brightness, color)
POST /api/ota Yes Start OTA update (HTTPS URL required)

POST /api/config example:

curl -X POST http://fresnel-beacon.local/api/config \
  -H "Content-Type: application/json" \
  -H "Authorization: Basic $(echo -n 'admin:fresnel' | base64)" \
  -d '{"speed_rpm":12.5,"mode":0,"brightness":0.8,"color":"0xFFA028"}'

POST /api/ota example:

curl -X POST http://fresnel-beacon.local/api/ota \
  -H "Content-Type: application/json" \
  -H "Authorization: Basic $(echo -n 'admin:fresnel' | base64)" \
  -d '{"url":"https://example.com/firmware.bin"}'

AP mode: When WiFi connection fails, device starts AP with SSID Fresnel-Beacon-XXYY and password derived from MAC address (printed in serial log on boot).

Security

  • HTTP Basic Auth — All mutating endpoints require authentication
  • HTTPS-only OTA — HTTP URLs rejected with 400 error
  • Input validation — All config parameters clamped to safe ranges
  • WiFi credential isolation — Separate struct with mutex-protected API
  • Rate limiting — Atomic counter for HTTP requests

Development Environment

  • ESP-IDF v5.3.x
  • Target: esp32s3
  • Flash via USB-C (native USB, no UART adapter needed)

Building

idf.py set-target esp32s3
idf.py build
idf.py flash

Testing

Host unit tests run without ESP-IDF or hardware:

gcc -Icomponents/led_driver/include -Icomponents/beacon_animation/include -I. test/test_beacon_math.c -lm -o test_beacon_math && ./test_beacon_math
gcc -Icomponents/led_driver/include -I. test/test_led_driver.c -lm -o test_led_driver && ./test_led_driver

Code Style

Format all C/H files before committing:

find components main test -name "*.c" -o -name "*.h" | xargs clang-format -i

Style config: .clang-format (LLVM-based, 4-space indent, 100 column limit).

CI

Three jobs on every push to main:

Job Description
test Compile and run host unit tests + formatting check
analyze cppcheck + clang-tidy static analysis
build-and-simulate ESP-IDF build, size report, Wokwi simulation

Releases are published automatically on v* tags.

License

MIT — see LICENSE.

About

ESP32-S3 lighthouse lamp with Fresnel lens and WS2812B LED matrix

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors