Firmware for a DIY smart birdhouse: an ESP32-based station periodically captures images with an OV2640-class camera and uploads them to the OnlyBirds cloud API. OnlyBirds is the viewer-facing platform; this repository is the on-device networking and imaging stack—the logic that attaches to the network and talks to OnlyBirds.
The design follows an open, hardware-flexible approach: you choose the board and enclosure; this codebase targets classic ESP32 bring-up (notably ESP32-CAM / AiThinker-style pin maps in-tree). Connectivity for uploads is cellular (SIM800-family GPRS) in the default production path; an optional Wi-Fi feature exists for lab bring-up and diagnostics.
| Crate | Role |
|---|---|
crates/openbirdhouse |
#![no_std] firmware binary: camera capture, HTTP to the device API, GSM session, deep sleep |
crates/esp32-camera-rs |
OV2640 + I²S camera pipeline pieces ported from Espressif esp32-camera (see per-file upstream comments) |
crates/esp32-gsm-rs |
SIM800-oriented AT/PPP helpers; modem flows trace TinyGSM (LGPL-3.0 crate—see NOTICE) |
The root Cargo.toml is a Cargo workspace; the flashable artifact is the openbirdhouse package.
- MCU / HAL: Espressif ESP32 (Xtensa) via
esp-hal1.1 withesp-rtosand Embassy (embassy-executor,embassy-time, optionalembassy-net). - Camera: JPEG capture path aligned with upstream
esp32-cameraregister tables, DMA sizing, and JPEG lane filtering. - Cellular: GPRS data path over a SIM800-class modem with timeouts and command ordering derived from TinyGSM sources.
- Memory: Internal DRAM reclaim for DMA budgets; PSRAM used as external heap where configured (
esp-alloc, project-specific layout). - Production cycle (default build): attach modem → optional firmware version sync against
DEVICE_API_BASE_URL→ capture JPEG →POSTto/device/photos/upload→ tear down radio → RTC deep sleep (~10 minutes, seeSTATION_CYCLE_INTERVAL_SECSinmain.rs). - Engineering build:
indoor-testenables Wi-Fi STA + DHCP and a small HTTP surface (picoserve) for/logsand photo endpoints while repeating the cellular upload loop without deep sleep when GSM is available.
- Rust toolchain with Xtensa support for
xtensa-esp32-none-elf(ESP Rust toolchain /espupas documented by esp-rs). espflash(used as the Cargo runner in.cargo/config.toml:espflash flash --monitor).
The firmware uses build-std for core + alloc on the Xtensa target (see .cargo/config.toml).
At workspace root, provide a .env file (loaded by crates/openbirdhouse/build.rs via dotenvy). Values are baked into the binary with cargo:rustc-env—do not commit secrets.
| Variable | Required | Purpose |
|---|---|---|
DEVICE_API_BASE_URL |
Yes | OnlyBirds API base URL (no trailing slash). Upload path is /device/photos/upload; firmware check uses /firmware/version. |
DEVICE_TOKEN |
Yes | Device bearer token issued by OnlyBirds. |
GSM_APN |
No (default internet) |
Operator APN for GPRS. |
GSM_USER / GSM_PASSWORD |
No | APN credentials when the operator requires them. |
WIFI_SSID / WIFI_PASSWORD |
Yes if --features indoor-test |
Station mode Wi-Fi for the test HTTP stack. |
For cellular uploads, prefer http:// base URLs if your backend allows it: HTTPS on port 443 is awkward on the GSM path; the client warns when https is configured for cellular (see DeviceBackendClient::warn_if_https_on_cellular).
Flash and monitor (runner is configured for ESP32 serial):
cargo run --release
# or with the feature:
cargo run --release --features indoor-testRelease profile favors size (opt-level = "s") with LTO and single codegen unit (Cargo.toml).
- Original Rust contributions in this repository: MIT (
LICENSE). - Portions of
esp32-camera-rsfollow Apache-2.0 (LICENSE-APACHE-2.0.txt). esp32-gsm-rsis LGPL-3.0 (LICENSE-LGPL-3.0.txt); static linking in distributed firmware may trigger LGPL obligations for that component—readNOTICE.- Dependency SPDX identifiers: see
Cargo.lockorcargo license.