Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/firmware.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ jobs:
# FEATURE_BIRDING product: same boards, Birding-edition firmware, own OTA channel
# (firmware-birding-<slug>.bin -- the slug must match FW_OTA_PREFIX + variant::SLUG).
- { env: blipscope-birding-s3-146, slug: birding-s3-146 }
# FEATURE_ANGLER product: same boards, Angler-edition (solunar fishing) firmware, own OTA
# channel (firmware-angler-<slug>.bin -- the slug must match FW_OTA_PREFIX + variant::SLUG).
- { env: blipscope-angler-s3-146, slug: angler-s3-146 }
# - { env: blipscope-lite-s3-128, slug: s3-128 }
# - { env: blipscope-pro-s3-175-amoled, slug: s3-175-amoled }
steps:
Expand Down
8 changes: 8 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ Unlike Space/EAM (rotating screens), the Seismic UI mirrors the **Aviation radar
- **Data / key:** the source is the eBird API 2.0; it needs the user's **own free token** (config `ebird-key`, sent as the `X-eBirdApiToken` header) — never a baked-in key, the same BYO pattern as the radar's OpenSky login and masked on the config page the same way (`*`-mask on GET, skip-if-masked on save). [BirdingFeedClient](src/birding/BirdingFeedClient.h) runs one worker over three endpoints (recent *notable* nearby, all recent nearby, nearby hotspots), all bounded by `dist`/`maxResults`; shapes + parsers in [BirdingModels.h](src/birding/BirdingModels.h). Nothing is polled until a key **and** a location are set.
- **UI:** a **hybrid** of the two existing shells — a dwell-timed auto-rotation that skips empty feeds AND swipe-to-navigate (from Space/EAM), **plus** a tap-to-inspect detail-card overlay on the radar / notable screens (from the Seismic/Aviation radar). Screens: sightings Radar, Notable, Big-Day species count, nearest Hotspot, Targets, Splash, Clock ([BirdingManager](src/birding/BirdingManager.h) + [BirdingScreens.cpp](src/birding/BirdingScreens.cpp)). The sightings radar uses static range rings, so [main.cpp](src/main.cpp) gates the aircraft PPI sweep out of the build (alongside EAM/Space/Seismic). ntfy alerts on two toggles (notable sighting / target species), seeded at boot via a seen-species set so the backlog never fires.

## FEATURE_ANGLER — a sixth product (Angler edition)

`-DFEATURE_ANGLER` (set on the `blipscope-angler-*` envs) swaps the radar app for the **Angler edition** — a desk fishing companion whose hero is an **on-device SOLUNAR "best bite times" forecast**. Its `build_src_filter` drops the radar-only TUs **and** `src/eam/`/`src/space/`/`src/seismic/`/`src/birding/`, and [main.cpp](src/main.cpp) picks `AnglerManager` at compile time. Everything lives in [src/angler/](src/angler/). The config page gains a `#elif defined(FEATURE_ANGLER)` branch in [ConfigurationWebServer.cpp](src/ConfigurationWebServer.cpp). OTA channel: `-DFW_OTA_PREFIX="angler-"`.

- **Shared astronomy core:** the sun/moon ephemeris that started life in Spacescope was moved to [src/astro/](src/astro/) (`space::astro::` namespace, unchanged) so Space **and** Angler can share it without either dragging in the other's app code. `src/astro/` is compiled **only** in the Space + Angler builds — every other env drops it in `build_src_filter`, always paired with `-<angler/>` since Angler links astro. Solunar is computed entirely from this core (moon transit/rise/set + phase); **no network at all** for the bite forecast.
- **Data (staged):** Stage 1 is fully on-device (solunar/sun/moon) and bakes in **no key and no backend**. Later stages layer keyless live data on top, mirroring `SeismicFeedClient`: **NOAA CO-OPS** tides + water temp (US; nearest station resolved in the config browser and cached to NVS), **Open-Meteo** weather + a computed barometer trend (worldwide), and **NDBC** buoys for real water temp / wave height. US-first, with Open-Meteo as the worldwide fallback; all sources keyless.
- **UI:** the **hybrid** shell (like Birding) — dwell-timed auto-rotation that skips empty screens, swipe-to-navigate, and a tap-to-inspect detail-card overlay; the hero is the Bite Forecast. Screens are user-toggleable via the `ang-screens` CSV checkbox grid (Stage 1: Bite / Moon / Sun / Clock, + internal Splash) ([AnglerManager](src/angler/AnglerManager.h) + [AnglerScreens.cpp](src/angler/AnglerScreens.cpp)). No PPI sweep, so [main.cpp](src/main.cpp) gates the sweep out of the FEATURE_ANGLER build. ntfy + optional speaker-chime alerts fire when a major feeding window opens (`ang-alert-bite` / `ang-chime`), edge-seeded at boot.

## The C3's three hard constraints — read before changing memory, networking, or touch

These applied to the now-**retired C3 Kit** SKU: a **single-core RISC-V** chip with a tight, fragmenting heap — most non-obvious shared code exists to live within that. The board is gone, but its guards stay in the tree (inert on S3, gated by capability flags), so this section stays as reference and a C3 could be revived: **don't "simplify" the guards away.** The S3 SKUs (dual-core + PSRAM) relax all three (full framebuffer, enrichment always-on, touch and network on separate cores) via the variant's capability flags rather than by deleting the guards:
Expand Down
55 changes: 51 additions & 4 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ build_flags =
; Shrink ESPAsyncWebServer's per-send buffer from 2x TCP_MSS (2872 B) to 1 KB so it
; fits a fragmented heap on the tightest board; roomier boards are unaffected.
-DASYNC_RESPONCE_BUFF_SIZE=1024
; Default source set: the radar app. The FEATURE_EAM (src/eam/) and FEATURE_SPACE (src/space/)
; clusters are separate compile-time products, so they're excluded here; the EAM / SPACE envs
; below override this filter to pull in their dir and drop the radar-only sources instead.
build_src_filter = +<*> -<eam/> -<space/>
; Default source set: the radar app. The FEATURE_EAM (src/eam/), FEATURE_SPACE (src/space/) and
; FEATURE_ANGLER (src/angler/) clusters are separate compile-time products, so they're excluded
; here; each edition env below overrides this filter to pull in its dir and drop the radar-only
; sources instead. src/astro/ (the shared sun/moon ephemeris) is used only by Space + Angler, so it
; is dropped everywhere it isn't needed -- always paired with -<angler/>, since Angler links astro.
build_src_filter = +<*> -<eam/> -<space/> -<astro/> -<angler/>
board_build.partitions = min_spiffs.csv
lib_deps =
lovyan03/LovyanGFX @ 1.2.21
Expand Down Expand Up @@ -122,6 +124,8 @@ build_src_filter =
-<Logbook.cpp>
-<models/>
-<space/>
-<astro/>
-<angler/>

; ===================== Spacescope (live space-data monitor) ===========
; A third compile-time PRODUCT from the same repo and boards: -DFEATURE_SPACE swaps the radar app
Expand Down Expand Up @@ -161,6 +165,7 @@ build_src_filter =
-<Logbook.cpp>
-<models/>
-<eam/>
-<angler/>

; ===================== Seismic edition (USGS earthquake radar) ========
; A fourth compile-time PRODUCT from the same repo and boards: -DFEATURE_SEISMIC swaps the radar app
Expand Down Expand Up @@ -195,6 +200,8 @@ build_src_filter =
-<models/>
-<eam/>
-<space/>
-<astro/>
-<angler/>

; ===================== Birding edition (eBird sightings radar) ========
; A compile-time PRODUCT from the same repo and boards: -DFEATURE_BIRDING swaps the radar app for the
Expand Down Expand Up @@ -230,6 +237,46 @@ build_src_filter =
-<eam/>
-<space/>
-<seismic/>
-<astro/>
-<angler/>

; ===================== Angler edition (solunar fishing forecast) ======
; A compile-time PRODUCT from the same repo and boards: -DFEATURE_ANGLER swaps the radar app for the
; Angler edition (src/angler/) -- a desk fishing companion. Its hero is an on-device SOLUNAR "best
; bite times" forecast computed from the shared sun/moon ephemeris (src/astro/, reused from
; Spacescope) with NO network at all; later stages layer keyless live data (NOAA CO-OPS tides +
; water temp, Open-Meteo weather/barometer trend, NDBC buoys) on top. Reuses all the shared infra
; (display, Wi-Fi, web config, storage, HTTP/TLS, OTA, ntfy) but NOT the radar/aircraft/ADS-B code
; or the EAM/Space/Seismic/Birding clusters, which build_src_filter strips (src/astro/ is kept). It
; bakes in NO key -- NOAA + Open-Meteo are keyless. FW_OTA_PREFIX -> firmware-angler-<slug>.bin.
; Runs on the S3 1.46".
[env:blipscope-angler-s3-146]
extends = common
board = esp32-s3-devkitc-1
board_build.arduino.memory_type = qio_opi ; 16 MB QIO flash + 8 MB OCTAL PSRAM (the R8)
board_build.flash_size = 16MB
board_upload.flash_size = 16MB
board_build.partitions = default_16MB.csv ; 16 MB gives OTA room
build_flags =
${common.build_flags}
-DBLIPSCOPE_VARIANT_S3_146
-DFEATURE_ANGLER
-DFW_OTA_PREFIX=\"angler-\"
-DBOARD_HAS_PSRAM
-DARDUINO_USB_MODE=1
-DARDUINO_USB_CDC_ON_BOOT=1 ; native USB-CDC: upload + monitor over the USB-C port
build_src_filter =
+<*>
-<AircraftManager.cpp>
-<MqttPublisher.cpp>
-<SpecialAircraft.cpp>
-<AircraftInfoFields.cpp>
-<Logbook.cpp>
-<models/>
-<eam/>
-<space/>
-<seismic/>
-<birding/>

; ===================== Assembled S3 tiers (TODO) ======================
; Added at hardware bring-up: each needs a variant header in include/variants/
Expand Down
Loading
Loading