@@ -122,10 +122,21 @@ bool otaCheckGithub() {
122122 filter ["tag_name" ] = true;
123123 filter ["assets" ][0 ]["name" ] = true;
124124 filter ["assets" ][0 ]["browser_download_url" ] = true;
125- JsonDocument doc ;
126- DeserializationError err = deserializeJson (doc , https .getStream (), DeserializationOption ::Filter (filter ));
125+ // Buffer the body before parsing. Reading the (large) release JSON straight
126+ // off the TLS stream is fragile -- a mid-transfer stall (seen on the check
127+ // that runs right after an STM flash) surfaces as "bad API response"
128+ // (IncompleteInput). getString() reads the whole body within the timeout so
129+ // the parser sees it intact; the error detail makes any recurrence concrete
130+ // (and is NOT an "up to date" signal).
131+ String body = https .getString ();
127132 https .end ();
128- if (err ) { otaSetStatus ("check: bad API response" ); return false; }
133+ JsonDocument doc ;
134+ DeserializationError err = deserializeJson (doc , body , DeserializationOption ::Filter (filter ));
135+ if (err ) {
136+ Serial .printf ("[OTA] api parse failed: %s (body=%u B)\n" , err .c_str (), (unsigned )body .length ());
137+ otaSetStatus ("check: bad API response (%s)" , err .c_str ());
138+ return false;
139+ }
129140
130141 tag = (const char * )(doc ["tag_name" ] | "" );
131142 for (JsonObject a : doc ["assets" ].as < JsonArray > ()) {
@@ -171,12 +182,18 @@ bool otaCheckGithub() {
171182 // a valid health signal for the post-update watchdog (otaHealthService()).
172183 g_cloud_ok = true;
173184
174- char espinfo [44 ], stminfo [44 ];
175- if (ota_esp_available ) snprintf (espinfo , sizeof espinfo , "%s->%s" , FW_VERSION , ota_esp_version .c_str ());
176- else snprintf (espinfo , sizeof espinfo , "%s ok ", FW_VERSION );
177- if (ota_stm_available ) snprintf (stminfo , sizeof stminfo , "%s->%s" , stm_fw_version .c_str (), ota_stm_version .c_str ());
178- else snprintf (stminfo , sizeof stminfo , "%s ok" , stm_fw_version .c_str ());
179- otaSetStatus ("ESP %s | STM %s" , espinfo , stminfo );
185+ if (!ota_esp_available && !ota_stm_available ) {
186+ // Both current -- the common, friendly "nothing to do" result.
187+ otaSetStatus ("Up to date (ESP %s, STM %s)" , FW_VERSION , stm_fw_version .c_str ());
188+ } else {
189+ // Something newer is available (and about to be applied below) -- show what.
190+ char espinfo [44 ], stminfo [44 ];
191+ if (ota_esp_available ) snprintf (espinfo , sizeof espinfo , "%s->%s" , FW_VERSION , ota_esp_version .c_str ());
192+ else snprintf (espinfo , sizeof espinfo , "%s ok ", FW_VERSION );
193+ if (ota_stm_available ) snprintf (stminfo , sizeof stminfo , "%s->%s" , stm_fw_version .c_str (), ota_stm_version .c_str ());
194+ else snprintf (stminfo , sizeof stminfo , "%s ok" , stm_fw_version .c_str ());
195+ otaSetStatus ("Update available: ESP %s | STM %s" , espinfo , stminfo );
196+ }
180197 return true;
181198}
182199
@@ -398,15 +415,21 @@ void otaAutoService() {
398415
399416 if (stm_flash_busy ) return ;
400417 if (WiFi .getMode () != WIFI_STA || WiFi .status () != WL_CONNECTED ) return ;
401- if ((long )(millis () - nextCheck ) < 0 ) return ;
402418
403- // Only act when idle. Don't advance the timer if busy, so we retry promptly
404- // once the current pass/stream/upload finishes (passes last only seconds).
419+ // A manual "check now" (config-page button) bypasses the interval timer; the
420+ // periodic check otherwise waits for nextCheck to elapse.
421+ bool manual = ota_check_now ;
422+ if (!manual && (long )(millis () - nextCheck ) < 0 ) return ;
423+
424+ // Only act when idle. Don't advance the timer or consume the manual request if
425+ // busy, so it retries promptly once the current pass/stream/upload finishes
426+ // (passes last only seconds).
405427 bool idle = !g_run_active && !stream_active &&
406428 (uploadQueue == nullptr || uxQueueMessagesWaiting (uploadQueue ) == 0 );
407429 if (!idle ) return ;
408430
409- nextCheck = millis () + OTA_CHECK_INTERVAL_MS ; // schedule the next check regardless of outcome
431+ ota_check_now = false; // consume the manual request (if any)
432+ nextCheck = millis () + OTA_CHECK_INTERVAL_MS ; // schedule the next periodic check regardless of outcome
410433
411434 if (!otaCheckGithub ()) return ;
412435
0 commit comments