@@ -68,11 +68,11 @@ def save_config(config):
6868 log .info ('Configuration saved; mode=%r host=%r' , config .get ('mode' ), config .get ('host' ) or 'local' )
6969
7070# --- Command Execution ---
71- def run_commands_local (cmds ):
71+ def run_commands_local (cmds , timeout_seconds = 5 ):
7272 results = []
7373 for cmd in cmds :
7474 try :
75- proc = subprocess .run (cmd , shell = True , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , text = True , timeout = 5 )
75+ proc = subprocess .run (cmd , shell = True , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , text = True , timeout = timeout_seconds )
7676 if proc .returncode != 0 :
7777 log .warning ('Local command failed (rc=%s): %s :: %s' , proc .returncode , cmd , proc .stdout .strip ())
7878 results .append (f"Error: { proc .stdout .strip ()} " )
@@ -83,7 +83,7 @@ def run_commands_local(cmds):
8383 results .append ("Error: An internal error occurred while executing a local command." )
8484 return results
8585
86- def run_commands_remote (cmds , config ):
86+ def run_commands_remote (cmds , config , timeout_seconds = 5 ):
8787 ssh = paramiko .SSHClient ()
8888 ssh .set_missing_host_key_policy (paramiko .AutoAddPolicy ())
8989 results = []
@@ -109,7 +109,7 @@ def run_commands_remote(cmds, config):
109109 ssh .connect (config .get ('host' ), username = config .get ('user' ), password = pwd , key_filename = key_filepath , timeout = 10 , banner_timeout = 15 , auth_timeout = 15 , look_for_keys = False )
110110
111111 for cmd in cmds :
112- stdin , stdout , stderr = ssh .exec_command (cmd , timeout = 5 )
112+ stdin , stdout , stderr = ssh .exec_command (cmd , timeout = timeout_seconds )
113113 err_out = stderr .read ().decode ('utf-8' ).strip ()
114114 std_out = stdout .read ().decode ('utf-8' ).strip ()
115115
@@ -193,39 +193,52 @@ def get_ntp():
193193@app .route ('/api/gps' )
194194def get_gps ():
195195 config = load_config ()
196- cmd = ["timeout 3 gpspipe -w -n 12" ]
196+ # Keep sample collection long enough to gather TPV/SKY reliably on slower receivers.
197+ cmd = ["timeout 8 gpspipe -w -n 8" ]
197198
198199 if config .get ("mode" ) == "local" :
199- gps_out = run_commands_local (cmd )[0 ]
200+ gps_out = run_commands_local (cmd , timeout_seconds = 10 )[0 ]
200201 else :
201- gps_out = run_commands_remote (cmd , config )[0 ]
202+ gps_out = run_commands_remote (cmd , config , timeout_seconds = 10 )[0 ]
202203
203204 satellites = []
204205 gps_time = "Waiting for lock..."
205206 error = None
207+ parse_source = gps_out or ""
208+ if gps_out and gps_out .startswith ('Error:' ):
209+ # Non-zero exit (often timeout) may still include usable JSON output.
210+ parse_source = gps_out [len ('Error:' ):].lstrip ()
211+
206212 if gps_out and (gps_out .startswith ('Error:' ) or "command not found" in gps_out .lower ()):
207213 error = gps_out
208214 if config .get ("mode" ) == "local" and "gpspipe" in gps_out and "not found" in gps_out .lower ():
209215 error = "Local GPS support is not installed in this image. Rebuild with INSTALL_GPSD_CLIENTS=true to enable gpspipe, or switch to Remote mode."
210216 gps_time = "Local GPS support not installed"
211217
212- if gps_out and not error :
213- for line in gps_out .strip ().split ('\n ' ):
218+ if parse_source :
219+ parsed_any = False
220+ for line in parse_source .strip ().split ('\n ' ):
214221 if not line :
215222 continue
216223 try :
217224 data = json .loads (line )
218225 if data .get ("class" ) == "SKY" :
219226 if "satellites" in data :
220227 satellites = data ["satellites" ]
228+ parsed_any = True
221229 elif data .get ("class" ) == "TPV" and "time" in data :
222230 gps_time = data .get ("time" )
231+ parsed_any = True
223232 except json .JSONDecodeError as e :
224233 log .debug ('GPS: could not parse line as JSON: %s' , e )
225234 except Exception as e :
226235 log .exception ('GPS: unexpected error parsing line: %s' , e )
227236 error = "GPS parsing error occurred"
228237
238+ # If we recovered useful data from a timeout-wrapped command, do not surface an error.
239+ if parsed_any and error and isinstance (error , str ) and error .startswith ('Error:' ):
240+ error = None
241+
229242 if error :
230243 log .warning ('GPS API returned error in %s mode: %s' , config .get ('mode' ), error )
231244 return jsonify ({"satellites" : satellites , "gps_time" : gps_time , "error" : error })
0 commit comments