V2.3.16: streaming FTPS + BMP390 cal fix + 4MB partition + polish
Summary
Seven small wins. One experiment tried and reverted with rationale documented in the commit message.
Headline fixes
-
Streaming FTPS upload (zero-copy) - Replaces
applog_snapshot's malloc-the-entire-ring pattern with a non-allocating iterator that returns segment pointers directly into ring memory. Body sent in 4 KB chunks straight from the ring; no body buffer malloc. Saves ~60 KB internal DRAM during the upload window on Heltec (V2.3.15 had crawled tomin_free=276 bytesat full ring; V2.3.16 stays around 3 KB - 10x improvement). On FeatherS3-D the 1 MB ring no longer needs a 1 MB body buffer either. -
BMP390 calibration typo fix -
par_T1divisor was2.52e-2instead of2^-8(=0.00390625, i.e. *256). Latent typo since V2.3.6 driver was first written. Surfaced 2026-05-10 the first time a BMP390 was actually wired in production - reported pressure was ~25 % high (1287 hPa vs actual 1024 hPa). Cross-checked all other 13 calibration constants against Bosch SDK + Adafruit BMP3xx library; onlypar_T1had the typo. -
4 MB knock-off partition layout fix - V2.3.15 4 MB layout was
factory + ota_0, which only allowed ONE OTA cycle (factory -> ota_0) before subsequent OTAs failed withESP_ERR_OTA_PARTITION_CONFLICT. New layout:ota_0 + ota_1(no factory), 1.875 MB each. CABLE REFLASH REQUIRED to switch layouts (partition tables can not be safely OTA'd).
Polish + new features
-
4MB / 8MB Heltec distinction in OTA upload form: page now reads "Select a firmware .bin for Heltec WiFi Kit 32 (4MB)" or "(8MB)" or "FeatherS3" depending on which build is running. Pairs with V2.3.13 chip-ID validation.
-
BOARD: <name>boot-log line inapp_mainright after the version string. Makes serial-log forensics trivially unambiguous. -
FTP host:port parsing -
ftp_hostconfig field now accepts an optional:portsuffix (e.g.192.168.1.1:2121). Defaults to FTP control port 21 when absent or malformed. Only affects the control channel; the data channel still uses whatever port the server returns from PASV. -
openSenseMap access token field (
osm_access_token, NVS keyosm_tok, default empty). Mirrors the existingaqi_tokenpattern. When set, send_osm passes the token asAuthorization: Bearer <token>. OSM recently added an opt-in "require authentication" toggle per box on their dashboard - this lets uploads continue when that toggle is on.
Reverted experiment - long-lived HTTPS handles
V2.3.16-pre2 introduced file-static cached esp_http_client_handle_t per target with save_client_session=true, hoping to eliminate the per-cycle PSA crypto leak by reusing TLS sessions across cycles. Bench-tested 2026-05-10 - empirically 2.8x slower per cycle (10 s -> 28 s) because cloud servers close keep-alive after ~60-120 s vs our 150 s cycle interval, and esp_http_client does NOT actually use the saved session ticket on reconnect (cert validation fires on every retry). Reverted. PSA leak mitigation continues via V2.3.15's defensive infrastructure (slot bump, nuclear PSA reset, preemptive stall reset).
Bench validation
- Genuine Heltec V2 (8 MB), V2.3.16-pre1 (streaming only): 8 clean FTPS uploads over 2 h, free heap stable at ~125 KB.
- Dust node FeatherS3-D, V2.3.16: BMP390 reads correct pressure, all HTTPS targets clean.
- China 4 MB knock-off, V2.3.16: cable-flashed cleanly with new dual-OTA layout, OTA cycling now works.
Artefacts
15 files: 5 per board (geiger_v2_<board>.bin, geiger_v2_merged_<board>.bin, bootloader_<board>.bin, partition-table_<board>.bin, ota_data_initial_<board>.bin) for each of heltec_v2 (genuine 8 MB), heltec_v2_4mb (knock-off 4 MB), feathers3_d (UM FeatherS3, ESP32-S3 + PSRAM).
For OTA: use the geiger_v2_<board>.bin (~1.2 MB).
For first-flash via cable at offset 0x0: use the geiger_v2_merged_<board>.bin (~1.3 MB).
Existing 4 MB knock-off devices on V2.3.15: cable-flash required to upgrade to V2.3.16's new dual-OTA partition layout. Subsequent V2.3.16+ updates cycle cleanly via OTA.