From fec399c75f302b899947ce550c834efd0eeb4440 Mon Sep 17 00:00:00 2001 From: SEMU Admin <28569967+semuadmin@users.noreply.github.com> Date: Wed, 29 Jul 2026 22:16:47 +0100 Subject: [PATCH 1/3] remove redundant CLI args --- RELEASE_NOTES.md | 7 +++++ src/pygpsclient/__main__.py | 44 +++--------------------------- src/pygpsclient/_version.py | 2 +- src/pygpsclient/app.py | 53 +++++++++---------------------------- src/pygpsclient/globals.py | 1 - 5 files changed, 23 insertions(+), 84 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 93030812..0c86fb72 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,12 @@ # PyGPSClient Release Notes +### RELEASE 1.7.3 + +FIXES: + +1. Fix for unattended UI lag issue. +1. Remove redundant CLI arguments relating to disused SPARTN client. + ### RELEASE 1.7.2 FIXES: diff --git a/src/pygpsclient/__main__.py b/src/pygpsclient/__main__.py index b243c121..f62134db 100644 --- a/src/pygpsclient/__main__.py +++ b/src/pygpsclient/__main__.py @@ -22,12 +22,7 @@ from pygpsclient._version import __version__ as VERSION from pygpsclient.app import App -from pygpsclient.globals import ( - APPNAME, - CONFIGFILE, - SPARTN_BASEDATE_CURRENT, - SPARTN_BASEDATE_DATASTREAM, -) +from pygpsclient.globals import APPNAME, CONFIGFILE from pygpsclient.strings import EPILOG @@ -52,32 +47,11 @@ def main(): help="User-defined GNSS receiver port", default=SUPPRESS, ) - ap.add_argument( - "-S", - "--spartnport", - help="User-defined SPARTN receiver port", - default=SUPPRESS, - ) ap.add_argument( "--mqapikey", help="MapQuest API Key", default=SUPPRESS, ) - ap.add_argument( - "--mqttclientid", - help="MQTT Client ID", - default=SUPPRESS, - ) - ap.add_argument( - "--mqttclientregion", - help="MQTT Client Region", - default=SUPPRESS, - ) - ap.add_argument( - "--mqttclientmode", - help="MQTT Client Mode (0 - IP, 1 - L-Band)", - default=SUPPRESS, - ) ap.add_argument( "--ntripcasteruser", help="NTRIP Caster authentication user", @@ -88,26 +62,14 @@ def main(): help="NTRIP Caster authentication password", default=SUPPRESS, ) - ap.add_argument( - "--spartnkey", - help="SPARTN message decryption key", - default=SUPPRESS, - ) - ap.add_argument( - "--spartnbasedate", - help=f"SPARTN message decryption timetag ({SPARTN_BASEDATE_CURRENT} = \ - current datetime, {SPARTN_BASEDATE_DATASTREAM} = use timetags from data stream)", - type=int, - default=SUPPRESS, - ) ap.add_argument( "--tlspempath", - help="Fully qualified path to TLS PEM (private key/certificate) file", + help="Fully qualified path to TLS PEM (private key/certificate) file used by socket server", default=SUPPRESS, ) ap.add_argument( "--tlscrtpath", - help="Fully qualified path to TLS CRT (certificate) file", + help="Fully qualified path to TLS CRT (certificate) file used by socket client", default=SUPPRESS, ) ap.add_argument( diff --git a/src/pygpsclient/_version.py b/src/pygpsclient/_version.py index 24f75b4c..d1a925ac 100644 --- a/src/pygpsclient/_version.py +++ b/src/pygpsclient/_version.py @@ -8,4 +8,4 @@ :license: BSD 3-Clause """ -__version__ = "1.7.2" +__version__ = "1.7.3" diff --git a/src/pygpsclient/app.py b/src/pygpsclient/app.py index 96c31b1b..4470c22d 100644 --- a/src/pygpsclient/app.py +++ b/src/pygpsclient/app.py @@ -3,20 +3,18 @@ PyGPSClient - Main tkinter application class. -Essentially the 'Model' in a nominal MVC (Model-View-Controller) +Essentially the 'Controller' in a nominal MVC (Model-View-Controller) architecture. -- Loads configuration from json file (if available) -- Instantiates all frames, widgets, and protocol handlers. +- Instantiates all frames and widgets via subclasses ('View'). +- Instantiates all protocol handlers. +- Maintains central dictionary of current key navigation data as + `gnss_status`, for use by user-selectable widgets ('Model'). - Maintains state of all user-selectable widgets. - Maintains state of all Toplevel dialogs. -- Maintains state of all threaded protocol handler processes. +- Maintains state of all threaded protocol handler and server processes. - Maintains state of serial and RTK connections. -- Handles event-driven data processing of navigation data placed on - input message queue by stream handler and assigns to appropriate - protocol handler. -- Maintains central dictionary of current key navigation data as - `gnss_status`, for use by user-selectable widgets. +- Handles configuration load, save and update. Global logging configuration is defined in __main__.py. To enable module logging, this and other subsidiary modules can use: @@ -74,8 +72,6 @@ CMDINITDELAY, CMDPAUSE, CONFIGFILE, - CONNECTED_SPARTNIP, - CONNECTED_SPARTNLB, DISCONNECTED, ERRCOL, FRAME, @@ -91,7 +87,6 @@ OKCOL, RTCMSTR, SOCKSERVER_MAX_CLIENTS, - SPARTN_EVENT, SPARTN_PROTOCOL, STATUS_PRIORITY, STATUS_TIMEOUT, @@ -232,6 +227,9 @@ def __init__(self, **kwargs): self.recording = False # RecordDialog status self.recording_type = 0 # 0 = TTY ONLY, 1 = UBX/NMEA self.ntriprtcmstr = RTCMSTR + self._gui_refresh_int = int( + self.configuration.get("guiupdateinterval_f") * 1000 + ) # open database if database recording enabled dbpath = self.configuration.get("databasepath_s") @@ -370,7 +368,6 @@ def _attach_events(self): self.bind(GNSS_TIMEOUT_EVENT, self.on_gnss_timeout) self.bind(GNSS_ERR_EVENT, self.on_stream_error) self.bind(NTRIP_EVENT, self.on_ntrip_read) - self.bind(SPARTN_EVENT, self.on_spartn_read) self.bind_all("", self.on_exit) self.bind_all("", self.on_killswitch) # also bound in check_updates @@ -583,15 +580,15 @@ def refresh_widgets(self): if hasattr(frm, "update_frame") and wdgdata[VISIBLE]: frm.update_frame() self.update() + self.update_idletasks() # update database if enabled (must be done in main App thread) if self.configuration.get("database_b"): self.sqlite_handler.load_data() if self.conn_status != DISCONNECTED or self.rtk_conn_status != DISCONNECTED: - update_interval = int(self.configuration.get("guiupdateinterval_f") * 1000) self.refresh_widget_timer = self.after( - update_interval, self.refresh_widgets + self._gui_refresh_int, self.refresh_widgets ) def start_dialog(self, dlg: str): @@ -824,32 +821,6 @@ def on_ntrip_read(self, event): # pylint: disable=unused-argument except (SerialException, SerialTimeoutException) as err: self.set_status_label(f"Error sending to device {err}", ERRCOL) - def on_spartn_read(self, event): # pylint: disable=unused-argument - """ - EVENT TRIGGERED - Action on <> event - data available on SPARTN queue. - - :param event event: read event - """ - - try: - raw_data, parsed_data = self.spartn_inqueue.get(False) - if raw_data is not None and parsed_data is not None: - self.send_to_device(raw_data) - if self._rtk_conn_status == CONNECTED_SPARTNLB: - source = "LBAND>>" - elif self._rtk_conn_status == CONNECTED_SPARTNIP: - source = "MQTT>>" - else: - source = "OTHER>>" - self.console_outqueue.put((raw_data, parsed_data, source)) - self.spartn_inqueue.task_done() - - except Empty: - pass - except (SerialException, SerialTimeoutException) as err: - self.set_status_label(f"Error sending to device {err}", ERRCOL) - def update_ntrip_status(self, status: bool, msgt: tuple | NoneType = None): """ Update NTRIP configuration dialog connection status. diff --git a/src/pygpsclient/globals.py b/src/pygpsclient/globals.py index a9ed6ae1..024efe9d 100644 --- a/src/pygpsclient/globals.py +++ b/src/pygpsclient/globals.py @@ -242,7 +242,6 @@ SPARTN_DEFAULT_KEY = "abcd1234abcd1234abcd1234abcd1234" SPARTN_EOF_EVENT = "<>" SPARTN_ERR_EVENT = "<>" -SPARTN_EVENT = "<>" SPARTN_KEYLEN = 16 SPARTN_OUTPORT = 8883 SPARTN_PPREGIONS = ("eu", "us", "jp", "kr", "au") From 16720fd4969d6cf302557bbfd59c66503582892f Mon Sep 17 00:00:00 2001 From: SEMU Admin <28569967+semuadmin@users.noreply.github.com> Date: Fri, 31 Jul 2026 09:26:05 +0100 Subject: [PATCH 2/3] remove redundant spartn queues --- README.md | 16 +++++++++------- src/pygpsclient/app.py | 2 -- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index b83d5273..7b061fc7 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ [Mapquest API Key](#mapquestapi) | [User-defined Presets](#userdefined) | [CLI Utilities](#cli) | -[Troubleshooting](#troubleshoot) | +[Troubleshooting & Known Issues](#troubleshoot) | [License](#license) | [Author Information](#author) @@ -508,17 +508,19 @@ The `pygnssutils` and `pyubxutils` libraries which underpin many of the function For further details, refer to the `pygnssutils` homepage at [https://github.com/semuconsulting/pygnssutils](https://github.com/semuconsulting/pygnssutils) or `pyubxutils` homepage at [https://github.com/semuconsulting/pyubxutils](https://github.com/semuconsulting/pyubxutils). --- -## Troubleshooting +## Troubleshooting and Known Issues -1. **NB:** The latest version of Python for MacOS (>=3.14.5) comes with a new version of tkinter (9.0). There appear to be fairly serious performance issues with this version on MacOS Tahoe which render the PyGPSClient UI somewhat sluggish. For the time being, it is recommended that users use >=3.14.4. This issue does *not* affect other operating systems or Python apps not using tkinter. +1. There is a known issue with PyGPSClient GUI refreshes becoming progressively slower if the app is left unattended (_i.e. no user interaction_) for an extended period - typically 30 minutes or more. The issue is more pronounced on low-end SBC platforms like the Raspberry Pi. **Underlying processing (including message parsing and datalogging) is unaffected**, and the GUI can generally be 'woken up' within a few seconds via a simple user interaction e.g. resizing the main panel. The root cause of this issue is under investigation, but is believed to be related to tkinter idle event processing. -2. If you encounter persistent `WARNING>>Error parsing data stream Serial stream terminated unexpectedly` messages in the console, this may be indicative of insufficient serial port bandwidth (baudrate or timeout) for the current output message cohort (*particularly if this includes Ephemera or Observation data*). Try increasing the baudrate in the first instance. +2. **NB:** The latest version of Python for MacOS (>=3.14.5) comes with a new version of tkinter (9.0). There appear to be fairly serious performance issues with this version on MacOS Tahoe which render the PyGPSClient GUI somewhat sluggish. For the time being, it is recommended that users use >=3.14.4. This issue does *not* affect other operating systems or Python apps not using tkinter. -3. Most [budget USB-UART adapters](https://www.amazon.co.uk/DSD-TECH-adapter-FT232RL-Compatible/dp/B07BBPX8B8?ref_=ast_sto_dp) (e.g. FT232, CH345, CP2102, *including those embedded on development boards*) have a bandwidth limit of around 3Mbps (≈ 375000 baud) and may not work reliably above 230600 baud, even if the receiver supports higher baud rates. If you're using an adapter and notice significant message corruption (e.g. frequent `WARNING>>..invalid checksum` messages), try reducing the baud rate to a maximum 230600. +3. If you encounter persistent `WARNING>>Error parsing data stream Serial stream terminated unexpectedly` messages in the console, this may be indicative of insufficient serial port bandwidth (baudrate or timeout) for the current output message cohort (*particularly if this includes raw Ephemerides or Observation data*). Try increasing the baudrate in the first instance. -4. Some Linux Wayland platforms appear to require Toplevel dialog windows to be non-transient (`transient_dialog_b: 0`) for the window 'maximise' icon to work properly. +4. Most [budget USB-UART adapters](https://www.amazon.co.uk/DSD-TECH-adapter-FT232RL-Compatible/dp/B07BBPX8B8?ref_=ast_sto_dp) (e.g. FT232, CH345, CP2102, *including those embedded on development boards*) have a bandwidth limit of around 3Mbps (≈ 375000 baud) and may not work reliably above 230600 baud, even if the receiver supports higher baud rates. If you're using an adapter and notice significant message corruption (e.g. frequent `WARNING>>..invalid checksum` messages), try reducing the baud rate to a maximum 230600. -5. Some Homebrew-installed Python environments on MacOS can give rise to critical segmentation errors (*illegal memory access*) when shell subprocesses are invoked, due to the way permissions are implemented. This may, for example, affect About..Update functionality; the workaround is to update via a standard CLI `pip install --upgrade` command. +5. Some Linux Wayland platforms appear to require Toplevel dialog windows to be non-transient (`transient_dialog_b: 0`) for the window 'maximise' icon to work properly. + +6. Some Homebrew-installed Python environments on MacOS can give rise to critical segmentation errors (*illegal memory access*) when shell subprocesses are invoked, due to the way permissions are implemented. For this reason, application updates via the About..Update button are disabled on Homebrew environments; use the CLI `python3 -m pip install --upgrade pygpsclient` command instead. --- ## License diff --git a/src/pygpsclient/app.py b/src/pygpsclient/app.py index 4470c22d..581f326a 100644 --- a/src/pygpsclient/app.py +++ b/src/pygpsclient/app.py @@ -197,8 +197,6 @@ def __init__(self, **kwargs): self._server_status = -1 # socket server status -1 = inactive self.gnss_outqueue = Queue() # messages to GNSS receiver self.ntrip_inqueue = Queue() # messages from NTRIP source - self.spartn_inqueue = Queue() # messages from SPARTN correction rcvr - self.spartn_outqueue = Queue() # messages to SPARTN correction rcvr self.socket_inqueue = Queue() # message from socket self.socket_outqueue = Queue() # message to socket self.console_outqueue = Queue() # message to console From 852496f870bdc1be4de193d771975dfee63111ae Mon Sep 17 00:00:00 2001 From: SEMU Admin <28569967+semuadmin@users.noreply.github.com> Date: Sat, 1 Aug 2026 09:21:24 +0100 Subject: [PATCH 3/3] update readme --- README.md | 2 +- src/pygpsclient/strings.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7b061fc7..47ddf76f 100644 --- a/README.md +++ b/README.md @@ -510,7 +510,7 @@ For further details, refer to the `pygnssutils` homepage at [https://github.com/ --- ## Troubleshooting and Known Issues -1. There is a known issue with PyGPSClient GUI refreshes becoming progressively slower if the app is left unattended (_i.e. no user interaction_) for an extended period - typically 30 minutes or more. The issue is more pronounced on low-end SBC platforms like the Raspberry Pi. **Underlying processing (including message parsing and datalogging) is unaffected**, and the GUI can generally be 'woken up' within a few seconds via a simple user interaction e.g. resizing the main panel. The root cause of this issue is under investigation, but is believed to be related to tkinter idle event processing. +1. There is a known issue with PyGPSClient GUI refreshes becoming progressively slower on certain platforms if the app is left unattended (_i.e. no user interaction_) for an extended period - typically 30 minutes or more. The issue is more pronounced on low-end SBC platforms like the Raspberry Pi. **Underlying processing (including message parsing and datalogging) is unaffected**, and the GUI can generally be 'woken up' within a few seconds via a simple user interaction e.g. resizing the main panel. The root cause of this issue is under investigation, but as a workaround, users can try a) increasing the `guiupdateinterval_f` setting in the json configuration file, or b) hiding some or all user-selectable widgets until needed. 2. **NB:** The latest version of Python for MacOS (>=3.14.5) comes with a new version of tkinter (9.0). There appear to be fairly serious performance issues with this version on MacOS Tahoe which render the PyGPSClient GUI somewhat sluggish. For the time being, it is recommended that users use >=3.14.4. This issue does *not* affect other operating systems or Python apps not using tkinter. diff --git a/src/pygpsclient/strings.py b/src/pygpsclient/strings.py index e86805f7..6c605ac0 100644 --- a/src/pygpsclient/strings.py +++ b/src/pygpsclient/strings.py @@ -230,7 +230,7 @@ DLGTNMEA = "NMEA Configuration" DLGTNTRIP = "NTRIP Configuration" DLGTRECORD = "Configuration Command Recorder" -DLGTRINEX = "RINEX Conversion (EXPERIMENTAL)" +DLGTRINEX = "RINEX Conversion (BETA)" DLGTSERVER = "Server Configuration" DLGTSETTINGS = "Settings" DLGTTTY = "TTY Configuration"