pygnssutils 1.2.6__tar.gz → 1.2.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pygnssutils-1.2.6/src/pygnssutils.egg-info → pygnssutils-1.2.8}/PKG-INFO +19 -54
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/README.md +7 -45
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/pyproject.toml +12 -9
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/__init__.py +0 -2
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/_version.py +1 -1
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/gnssreader.py +20 -28
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/gnssstreamer_cli.py +0 -37
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/rinex_globals.py +1 -1
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/rinex_helpers.py +1 -1
- {pygnssutils-1.2.6 → pygnssutils-1.2.8/src/pygnssutils.egg-info}/PKG-INFO +19 -54
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils.egg-info/SOURCES.txt +0 -3
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils.egg-info/entry_points.txt +0 -1
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils.egg-info/requires.txt +6 -6
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/tests/test_cli.py +0 -5
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/tests/test_static.py +0 -18
- pygnssutils-1.2.6/src/pygnssutils/gnssmqttclient.py +0 -481
- pygnssutils-1.2.6/src/pygnssutils/gnssmqttclient_cli.py +0 -262
- pygnssutils-1.2.6/src/pygnssutils/mqttmessage.py +0 -74
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/LICENSE +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/setup.cfg +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/exceptions.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/globals.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/gnssntripclient.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/gnssntripclient_cli.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/gnssserver.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/gnssserver_cli.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/gnssstreamer.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/helpers.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/rawnav.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/rawnav_reader.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/rawnav_subframes_bds.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/rawnav_subframes_gal.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/rawnav_subframes_glo.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/rawnav_subframes_gps.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/rawnav_subframes_irn.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/rawnav_subframes_qzs.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/rawnav_subframes_sba.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/rinex_conv.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/rinex_conv_cli.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/rinex_conv_met.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/rinex_conv_nav.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/rinex_conv_obs.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils/socket_server.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils.egg-info/dependency_links.txt +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/src/pygnssutils.egg-info/top_level.txt +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/tests/test_gnssstreamer.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/tests/test_rawnav.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/tests/test_rinex.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/tests/test_rinex_defs.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/tests/test_rinex_parse.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/tests/test_socketwrapper.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/tests/test_sourcetable.py +0 -0
- {pygnssutils-1.2.6 → pygnssutils-1.2.8}/tests/test_stream.py +0 -0
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pygnssutils
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.8
|
|
4
4
|
Summary: GNSS Command Line Utilities
|
|
5
|
-
Author
|
|
6
|
-
|
|
5
|
+
Author: Steve Smith
|
|
6
|
+
Author-email: semuadmin@semuconsulting.com
|
|
7
|
+
Maintainer: Steve Smith
|
|
8
|
+
Maintainer-email: semuadmin@semuconsulting.com
|
|
7
9
|
License-Expression: BSD-3-Clause
|
|
8
10
|
Project-URL: homepage, https://github.com/semuconsulting/pygnssutils
|
|
9
11
|
Project-URL: documentation, https://www.semuconsulting.com/pygnssutils/
|
|
@@ -24,21 +26,22 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
24
26
|
Classifier: Programming Language :: Python :: 3.12
|
|
25
27
|
Classifier: Programming Language :: Python :: 3.13
|
|
26
28
|
Classifier: Programming Language :: Python :: 3.14
|
|
29
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
27
30
|
Classifier: Topic :: Utilities
|
|
28
31
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
29
32
|
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
30
33
|
Requires-Python: >=3.10
|
|
31
34
|
Description-Content-Type: text/markdown
|
|
32
35
|
License-File: LICENSE
|
|
33
|
-
Requires-Dist: certifi>=
|
|
34
|
-
Requires-Dist:
|
|
36
|
+
Requires-Dist: certifi>=2026.0.0
|
|
37
|
+
Requires-Dist: pynmeagps>=1.1.7
|
|
38
|
+
Requires-Dist: pyqgc>=1.0.0
|
|
39
|
+
Requires-Dist: pyrtcm>=1.2.0
|
|
40
|
+
Requires-Dist: pysbf2>=1.0.4
|
|
35
41
|
Requires-Dist: pyserial>=3.5
|
|
36
42
|
Requires-Dist: pyspartn>=1.0.8
|
|
37
|
-
Requires-Dist: pyubx2>=1.3.
|
|
38
|
-
Requires-Dist: pynmeagps>=1.1.5
|
|
39
|
-
Requires-Dist: pysbf2>=1.0.4
|
|
43
|
+
Requires-Dist: pyubx2>=1.3.7
|
|
40
44
|
Requires-Dist: pyubxutils>=1.0.6
|
|
41
|
-
Requires-Dist: pyqgc>=1.0.0
|
|
42
45
|
Requires-Dist: pyunigps>=1.0.0
|
|
43
46
|
Dynamic: license-file
|
|
44
47
|
|
|
@@ -51,7 +54,6 @@ pygnssutils
|
|
|
51
54
|
[gnssstreamer CLI](#gnssstreamer) |
|
|
52
55
|
[gnssserver CLI](#gnssserver) |
|
|
53
56
|
[gnssntripclient CLI](#gnssntripclient) |
|
|
54
|
-
[gnssmqttclient CLI](#gnssmqttclient) |
|
|
55
57
|
[socketserver](#socketserver) |
|
|
56
58
|
[RINEX Conversion](#rinexconvert) |
|
|
57
59
|
[RTK Demonstration](#rtkdemo) |
|
|
@@ -71,17 +73,14 @@ pygnssutils is an original series of Python GNSS utility classes and CLI tools b
|
|
|
71
73
|
|
|
72
74
|
Originally developed in support of the [PyGPSClient](https://github.com/semuconsulting/PyGPSClient) GUI GNSS application, the utilities provided by pygnssutils can also be used in their own right:
|
|
73
75
|
|
|
74
|
-
1. `GNSSReader` class. This is essentially an amalgamation of the `*Reader` classes in all the subsidiary parsers listed above, allowing the user to seamlessly stream any of NMEA, UBX, SBF, UNI, QGC
|
|
76
|
+
1. `GNSSReader` class. This is essentially an amalgamation of the `*Reader` classes in all the subsidiary parsers listed above, allowing the user to seamlessly stream any of NMEA, UBX, SBF, UNI, QGC and RTCM3 message protocols concurrently from a single stream.
|
|
75
77
|
1. `GNSSStreamer` class and its associated [`gnssstreamer`](#gnssstreamer) (*formerly `gnssdump`*) CLI utility. This is essentially a configurable bidirectional input/output wrapper around the `GNSSReader` class with flexible message formatting, filtering and output handling options for NMEA, UBX, SBF, UNI, QGC and RTCM3 protocols.
|
|
76
78
|
1. `GNSSSocketServer` class and its associated [`gnssserver`](#gnssserver) CLI utility. This implements a TCP Socket Server for GNSS data streams which is also capable of being run as a simple NTRIP Server/Caster.
|
|
77
79
|
1. `GNSSNTRIPClient` class and its associated [`gnssntripclient`](#gnssntripclient) CLI utility. This implements
|
|
78
80
|
a simple NTRIP Client which receives RTCM3 or SPARTN correction data from an NTRIP Server and (optionally) sends this to a
|
|
79
81
|
designated output stream.
|
|
80
|
-
1. `GNSSMQTTClient` class and its associated [`gnssmqttclient`](#gnssmqttclient) CLI utility. This implements
|
|
81
|
-
a simple SPARTN IP (MQTT) Client which receives SPARTN correction data from an SPARTN IP location service and (optionally) sends this to a
|
|
82
|
-
designated output stream.
|
|
83
82
|
1. `SocketServer` class based on the native Python `ThreadingTCPServer`. Capable of operating in two modes - Socket Server or NTRIP Caster. Provides two alternate client request handler classes - `ClientHandler` (HTTP) or `ClientHandlerTLS` (HTTPS).
|
|
84
|
-
1. `RinexConverter` class and its associated [`pyrinexconv`](#rinexconvert) CLI utility. This implements a binary GNSS data log file to RINEX text file conversion facility. **NB: RINEX conversion is currently an experimental
|
|
83
|
+
1. `RinexConverter` class and its associated [`pyrinexconv`](#rinexconvert) CLI utility. This implements a binary GNSS data log file to RINEX text file conversion facility. **NB: RINEX conversion is currently an experimental feature (*contributions and feedback welcome*)**
|
|
85
84
|
|
|
86
85
|
The pygnssutils homepage is located at [https://github.com/semuconsulting/pygnssutils](https://github.com/semuconsulting/pygnssutils).
|
|
87
86
|
|
|
@@ -97,18 +96,18 @@ The pygnssutils homepage is located at [https://github.com/semuconsulting/pygnss
|
|
|
97
96
|
|
|
98
97
|
Sphinx API Documentation in HTML format is available at [https://www.semuconsulting.com/pygnssutils](https://www.semuconsulting.com/pygnssutils).
|
|
99
98
|
|
|
100
|
-
Contributions welcome - please refer to [CONTRIBUTING.MD](https://github.com/semuconsulting/pygnssutils/blob/main/CONTRIBUTING.md).
|
|
99
|
+
Contributions _**from human beings**_ welcome - please refer to [CONTRIBUTING.MD](https://github.com/semuconsulting/pygnssutils/blob/main/CONTRIBUTING.md).
|
|
101
100
|
|
|
102
101
|
[Bug reports](https://github.com/semuconsulting/pygnssutils/blob/main/.github/ISSUE_TEMPLATE/bug_report.md) and [Feature requests](https://github.com/semuconsulting/pygnssutils/blob/main/.github/ISSUE_TEMPLATE/feature_request.md) - please use the templates provided. For general queries and advice, post a message to one of the [pygnssutils Discussions](https://github.com/semuconsulting/pygnssutils/discussions) channels.
|
|
103
102
|
|
|
104
|
-

|
|
105
104
|
|
|
106
105
|
---
|
|
107
106
|
## <a name="installation">Installation</a>
|
|
108
107
|
|
|
109
108
|

|
|
110
109
|
[](https://pypi.org/project/pygnssutils/)
|
|
111
|
-
[](https://clickpy.clickhouse.com/dashboard/pygnssutils)
|
|
112
111
|
|
|
113
112
|
`pygnssutils` is compatible with Python>=3.10.
|
|
114
113
|
|
|
@@ -182,7 +181,6 @@ class pygnssutils.gnssstreamer.GNSSStreamer(**kwargs)
|
|
|
182
181
|
- 0 = none (default)
|
|
183
182
|
- 1 = RTK NTRIP RTCM caster
|
|
184
183
|
- 2 = RTK NTRIP SPARTN caster
|
|
185
|
-
- 3 = RTK MQTT SPARTN source (see [gnssmqttclient](#gnssmqttclient) for MQTT client configuration details)
|
|
186
184
|
- 4 = serial port
|
|
187
185
|
- 5 = binary file.
|
|
188
186
|
|
|
@@ -472,41 +470,6 @@ gnssntripclient -h
|
|
|
472
470
|
|
|
473
471
|
Refer to the [Sphinx API documentation](https://www.semuconsulting.com/pygnssutils/pygnssutils.html#module-pygnssutils.gnssntripclient) for further details.
|
|
474
472
|
|
|
475
|
-
---
|
|
476
|
-
## <a name="gnssmqttclient">GNSSMQTTClient and gnssmqttclient CLI</a>
|
|
477
|
-
```
|
|
478
|
-
class pygnssutils.gnssmqttclient.GNSSMQTTClient(app=None, **kwargs)
|
|
479
|
-
```
|
|
480
|
-
|
|
481
|
-
The `GNSSMQTTClient` class provides a basic SPARTN IP (MQTT) Client capability and forms the basis of a [`gnssmqttclient`](#gnssmqttclient) CLI utility. It receives RTK correction data from a SPARTN IP (MQTT) location service (e.g. the u-blox / Thingstream PointPerfect service) and (optionally) sends this to a designated output stream.
|
|
482
|
-
|
|
483
|
-
### CLI Usage:
|
|
484
|
-
|
|
485
|
-
The `clientid` provided by the location service may be set as environment variable `MQTTCLIENTID`. If this environment variable is set and the TLS certificate (\*.crt) and key (\*.pem) files provided by the location service are placed in the user's `HOME` directory, the utility can use these as default settings and may be invoked without any arguments.
|
|
486
|
-
|
|
487
|
-
Assuming the Python 3 scripts (bin) directory is in your PATH, the CLI utility may be invoked from the shell thus (press CTRL-C to terminate):
|
|
488
|
-
|
|
489
|
-
```shell
|
|
490
|
-
gnssmqttclient --clientid yourclientid --server pp.services.u-blox.com --port 8883 --region eu --mode 0 --topic_ip 1 --topic_mga 1 --topic_key 1 --tlscrt '/Users/{your-user}/device-{your-clientid}-pp-cert.crt' --tlskey '/Users/{your-user}/device-{your-client-id}-pp-key.pem'} --spartndecode 0 --clioutput 0 --verbosity 2
|
|
491
|
-
```
|
|
492
|
-
```
|
|
493
|
-
2024-08-15 09:14:50.544 - INFO - pygnssutils.gnssmqttclient - Starting MQTT client with arguments {'server': 'pp.services.u-blox.com', 'port': 8883, 'clientid': 'your-client-id', 'region': 'eu', 'mode': 0, 'topic_ip': 1, 'topic_mga': 1, 'topic_key': 1, 'tlscrt': '/Users/myuser/device-your-client-id-pp-cert.crt', 'tlskey': '/Users/myuser/device-your-client-id-pp-key.pem', 'spartndecode': 0, 'output': None}.
|
|
494
|
-
2024-08-15 09:14:50.840 - INFO - pygnssutils.gnssmqttclient - RXM-SPARTN-KEY
|
|
495
|
-
2024-08-15 09:14:50.854 - INFO - pygnssutils.gnssmqttclient - MGA-INI-TIME-UTC
|
|
496
|
-
2024-08-15 09:14:50.858 - INFO - pygnssutils.gnssmqttclient - MGA-GPS-EPH
|
|
497
|
-
...
|
|
498
|
-
```
|
|
499
|
-
|
|
500
|
-
Command line arguments can be stored in a configuration file and invoked using the `-C` or `--config` argument. The location of the configuration file can be set in environment variable `GNSSMQTTCLIENT_CONF`.
|
|
501
|
-
|
|
502
|
-
For help and full list of optional arguments, type:
|
|
503
|
-
|
|
504
|
-
```shell
|
|
505
|
-
gnssmqttclient -h
|
|
506
|
-
```
|
|
507
|
-
|
|
508
|
-
Refer to the [pyspartn documentation](https://github.com/semuconsulting/pyspartn?tab=readme-ov-file#reading) for further details on decrypting encrypted (`eaf=1`) SPARTN payloads.
|
|
509
|
-
|
|
510
473
|
---
|
|
511
474
|
## <a name="socketserver">SocketServer</a>
|
|
512
475
|
|
|
@@ -671,6 +634,8 @@ semuadmin@semuconsulting.com
|
|
|
671
634
|
|
|
672
635
|

|
|
673
636
|
|
|
637
|
+
[ https://orcid.org/0009-0002-5751-8719](https://orcid.org/0009-0002-5751-8719)
|
|
638
|
+
|
|
674
639
|
`pygnssutils` is maintained entirely by unpaid volunteers. It receives no funding from advertising or corporate sponsorship. If you find the utility useful, please consider sponsoring the project with the price of a coffee...
|
|
675
640
|
|
|
676
641
|
[](https://buymeacoffee.com/semuconsulting)
|
|
@@ -7,7 +7,6 @@ pygnssutils
|
|
|
7
7
|
[gnssstreamer CLI](#gnssstreamer) |
|
|
8
8
|
[gnssserver CLI](#gnssserver) |
|
|
9
9
|
[gnssntripclient CLI](#gnssntripclient) |
|
|
10
|
-
[gnssmqttclient CLI](#gnssmqttclient) |
|
|
11
10
|
[socketserver](#socketserver) |
|
|
12
11
|
[RINEX Conversion](#rinexconvert) |
|
|
13
12
|
[RTK Demonstration](#rtkdemo) |
|
|
@@ -27,17 +26,14 @@ pygnssutils is an original series of Python GNSS utility classes and CLI tools b
|
|
|
27
26
|
|
|
28
27
|
Originally developed in support of the [PyGPSClient](https://github.com/semuconsulting/PyGPSClient) GUI GNSS application, the utilities provided by pygnssutils can also be used in their own right:
|
|
29
28
|
|
|
30
|
-
1. `GNSSReader` class. This is essentially an amalgamation of the `*Reader` classes in all the subsidiary parsers listed above, allowing the user to seamlessly stream any of NMEA, UBX, SBF, UNI, QGC
|
|
29
|
+
1. `GNSSReader` class. This is essentially an amalgamation of the `*Reader` classes in all the subsidiary parsers listed above, allowing the user to seamlessly stream any of NMEA, UBX, SBF, UNI, QGC and RTCM3 message protocols concurrently from a single stream.
|
|
31
30
|
1. `GNSSStreamer` class and its associated [`gnssstreamer`](#gnssstreamer) (*formerly `gnssdump`*) CLI utility. This is essentially a configurable bidirectional input/output wrapper around the `GNSSReader` class with flexible message formatting, filtering and output handling options for NMEA, UBX, SBF, UNI, QGC and RTCM3 protocols.
|
|
32
31
|
1. `GNSSSocketServer` class and its associated [`gnssserver`](#gnssserver) CLI utility. This implements a TCP Socket Server for GNSS data streams which is also capable of being run as a simple NTRIP Server/Caster.
|
|
33
32
|
1. `GNSSNTRIPClient` class and its associated [`gnssntripclient`](#gnssntripclient) CLI utility. This implements
|
|
34
33
|
a simple NTRIP Client which receives RTCM3 or SPARTN correction data from an NTRIP Server and (optionally) sends this to a
|
|
35
34
|
designated output stream.
|
|
36
|
-
1. `GNSSMQTTClient` class and its associated [`gnssmqttclient`](#gnssmqttclient) CLI utility. This implements
|
|
37
|
-
a simple SPARTN IP (MQTT) Client which receives SPARTN correction data from an SPARTN IP location service and (optionally) sends this to a
|
|
38
|
-
designated output stream.
|
|
39
35
|
1. `SocketServer` class based on the native Python `ThreadingTCPServer`. Capable of operating in two modes - Socket Server or NTRIP Caster. Provides two alternate client request handler classes - `ClientHandler` (HTTP) or `ClientHandlerTLS` (HTTPS).
|
|
40
|
-
1. `RinexConverter` class and its associated [`pyrinexconv`](#rinexconvert) CLI utility. This implements a binary GNSS data log file to RINEX text file conversion facility. **NB: RINEX conversion is currently an experimental
|
|
36
|
+
1. `RinexConverter` class and its associated [`pyrinexconv`](#rinexconvert) CLI utility. This implements a binary GNSS data log file to RINEX text file conversion facility. **NB: RINEX conversion is currently an experimental feature (*contributions and feedback welcome*)**
|
|
41
37
|
|
|
42
38
|
The pygnssutils homepage is located at [https://github.com/semuconsulting/pygnssutils](https://github.com/semuconsulting/pygnssutils).
|
|
43
39
|
|
|
@@ -53,18 +49,18 @@ The pygnssutils homepage is located at [https://github.com/semuconsulting/pygnss
|
|
|
53
49
|
|
|
54
50
|
Sphinx API Documentation in HTML format is available at [https://www.semuconsulting.com/pygnssutils](https://www.semuconsulting.com/pygnssutils).
|
|
55
51
|
|
|
56
|
-
Contributions welcome - please refer to [CONTRIBUTING.MD](https://github.com/semuconsulting/pygnssutils/blob/main/CONTRIBUTING.md).
|
|
52
|
+
Contributions _**from human beings**_ welcome - please refer to [CONTRIBUTING.MD](https://github.com/semuconsulting/pygnssutils/blob/main/CONTRIBUTING.md).
|
|
57
53
|
|
|
58
54
|
[Bug reports](https://github.com/semuconsulting/pygnssutils/blob/main/.github/ISSUE_TEMPLATE/bug_report.md) and [Feature requests](https://github.com/semuconsulting/pygnssutils/blob/main/.github/ISSUE_TEMPLATE/feature_request.md) - please use the templates provided. For general queries and advice, post a message to one of the [pygnssutils Discussions](https://github.com/semuconsulting/pygnssutils/discussions) channels.
|
|
59
55
|
|
|
60
|
-

|
|
61
57
|
|
|
62
58
|
---
|
|
63
59
|
## <a name="installation">Installation</a>
|
|
64
60
|
|
|
65
61
|

|
|
66
62
|
[](https://pypi.org/project/pygnssutils/)
|
|
67
|
-
[](https://clickpy.clickhouse.com/dashboard/pygnssutils)
|
|
68
64
|
|
|
69
65
|
`pygnssutils` is compatible with Python>=3.10.
|
|
70
66
|
|
|
@@ -138,7 +134,6 @@ class pygnssutils.gnssstreamer.GNSSStreamer(**kwargs)
|
|
|
138
134
|
- 0 = none (default)
|
|
139
135
|
- 1 = RTK NTRIP RTCM caster
|
|
140
136
|
- 2 = RTK NTRIP SPARTN caster
|
|
141
|
-
- 3 = RTK MQTT SPARTN source (see [gnssmqttclient](#gnssmqttclient) for MQTT client configuration details)
|
|
142
137
|
- 4 = serial port
|
|
143
138
|
- 5 = binary file.
|
|
144
139
|
|
|
@@ -428,41 +423,6 @@ gnssntripclient -h
|
|
|
428
423
|
|
|
429
424
|
Refer to the [Sphinx API documentation](https://www.semuconsulting.com/pygnssutils/pygnssutils.html#module-pygnssutils.gnssntripclient) for further details.
|
|
430
425
|
|
|
431
|
-
---
|
|
432
|
-
## <a name="gnssmqttclient">GNSSMQTTClient and gnssmqttclient CLI</a>
|
|
433
|
-
```
|
|
434
|
-
class pygnssutils.gnssmqttclient.GNSSMQTTClient(app=None, **kwargs)
|
|
435
|
-
```
|
|
436
|
-
|
|
437
|
-
The `GNSSMQTTClient` class provides a basic SPARTN IP (MQTT) Client capability and forms the basis of a [`gnssmqttclient`](#gnssmqttclient) CLI utility. It receives RTK correction data from a SPARTN IP (MQTT) location service (e.g. the u-blox / Thingstream PointPerfect service) and (optionally) sends this to a designated output stream.
|
|
438
|
-
|
|
439
|
-
### CLI Usage:
|
|
440
|
-
|
|
441
|
-
The `clientid` provided by the location service may be set as environment variable `MQTTCLIENTID`. If this environment variable is set and the TLS certificate (\*.crt) and key (\*.pem) files provided by the location service are placed in the user's `HOME` directory, the utility can use these as default settings and may be invoked without any arguments.
|
|
442
|
-
|
|
443
|
-
Assuming the Python 3 scripts (bin) directory is in your PATH, the CLI utility may be invoked from the shell thus (press CTRL-C to terminate):
|
|
444
|
-
|
|
445
|
-
```shell
|
|
446
|
-
gnssmqttclient --clientid yourclientid --server pp.services.u-blox.com --port 8883 --region eu --mode 0 --topic_ip 1 --topic_mga 1 --topic_key 1 --tlscrt '/Users/{your-user}/device-{your-clientid}-pp-cert.crt' --tlskey '/Users/{your-user}/device-{your-client-id}-pp-key.pem'} --spartndecode 0 --clioutput 0 --verbosity 2
|
|
447
|
-
```
|
|
448
|
-
```
|
|
449
|
-
2024-08-15 09:14:50.544 - INFO - pygnssutils.gnssmqttclient - Starting MQTT client with arguments {'server': 'pp.services.u-blox.com', 'port': 8883, 'clientid': 'your-client-id', 'region': 'eu', 'mode': 0, 'topic_ip': 1, 'topic_mga': 1, 'topic_key': 1, 'tlscrt': '/Users/myuser/device-your-client-id-pp-cert.crt', 'tlskey': '/Users/myuser/device-your-client-id-pp-key.pem', 'spartndecode': 0, 'output': None}.
|
|
450
|
-
2024-08-15 09:14:50.840 - INFO - pygnssutils.gnssmqttclient - RXM-SPARTN-KEY
|
|
451
|
-
2024-08-15 09:14:50.854 - INFO - pygnssutils.gnssmqttclient - MGA-INI-TIME-UTC
|
|
452
|
-
2024-08-15 09:14:50.858 - INFO - pygnssutils.gnssmqttclient - MGA-GPS-EPH
|
|
453
|
-
...
|
|
454
|
-
```
|
|
455
|
-
|
|
456
|
-
Command line arguments can be stored in a configuration file and invoked using the `-C` or `--config` argument. The location of the configuration file can be set in environment variable `GNSSMQTTCLIENT_CONF`.
|
|
457
|
-
|
|
458
|
-
For help and full list of optional arguments, type:
|
|
459
|
-
|
|
460
|
-
```shell
|
|
461
|
-
gnssmqttclient -h
|
|
462
|
-
```
|
|
463
|
-
|
|
464
|
-
Refer to the [pyspartn documentation](https://github.com/semuconsulting/pyspartn?tab=readme-ov-file#reading) for further details on decrypting encrypted (`eaf=1`) SPARTN payloads.
|
|
465
|
-
|
|
466
426
|
---
|
|
467
427
|
## <a name="socketserver">SocketServer</a>
|
|
468
428
|
|
|
@@ -627,6 +587,8 @@ semuadmin@semuconsulting.com
|
|
|
627
587
|
|
|
628
588
|

|
|
629
589
|
|
|
590
|
+
[ https://orcid.org/0009-0002-5751-8719](https://orcid.org/0009-0002-5751-8719)
|
|
591
|
+
|
|
630
592
|
`pygnssutils` is maintained entirely by unpaid volunteers. It receives no funding from advertising or corporate sponsorship. If you find the utility useful, please consider sponsoring the project with the price of a coffee...
|
|
631
593
|
|
|
632
594
|
[](https://buymeacoffee.com/semuconsulting)
|
|
@@ -5,8 +5,11 @@ build-backend = "setuptools.build_meta:__legacy__"
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pygnssutils"
|
|
7
7
|
dynamic = ["version"]
|
|
8
|
-
authors = [{ name = "Steve Smith", email = "semuadmin@semuconsulting.com" }]
|
|
9
|
-
maintainers = [
|
|
8
|
+
authors = [{ name = "Steve Smith" }, { email = "semuadmin@semuconsulting.com" }]
|
|
9
|
+
maintainers = [
|
|
10
|
+
{ name = "Steve Smith" },
|
|
11
|
+
{ email = "semuadmin@semuconsulting.com" },
|
|
12
|
+
]
|
|
10
13
|
description = "GNSS Command Line Utilities"
|
|
11
14
|
license = "BSD-3-Clause"
|
|
12
15
|
license-files = ["LICENSE"]
|
|
@@ -28,21 +31,22 @@ classifiers = [
|
|
|
28
31
|
"Programming Language :: Python :: 3.12",
|
|
29
32
|
"Programming Language :: Python :: 3.13",
|
|
30
33
|
"Programming Language :: Python :: 3.14",
|
|
34
|
+
"Programming Language :: Python :: 3.15",
|
|
31
35
|
"Topic :: Utilities",
|
|
32
36
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
33
37
|
"Topic :: Scientific/Engineering :: GIS",
|
|
34
38
|
]
|
|
35
39
|
|
|
36
40
|
dependencies = [
|
|
37
|
-
"certifi>=
|
|
38
|
-
"
|
|
41
|
+
"certifi>=2026.0.0",
|
|
42
|
+
"pynmeagps>=1.1.7",
|
|
43
|
+
"pyqgc>=1.0.0",
|
|
44
|
+
"pyrtcm>=1.2.0",
|
|
45
|
+
"pysbf2>=1.0.4",
|
|
39
46
|
"pyserial>=3.5",
|
|
40
47
|
"pyspartn>=1.0.8",
|
|
41
|
-
"pyubx2>=1.3.
|
|
42
|
-
"pynmeagps>=1.1.5",
|
|
43
|
-
"pysbf2>=1.0.4",
|
|
48
|
+
"pyubx2>=1.3.7",
|
|
44
49
|
"pyubxutils>=1.0.6",
|
|
45
|
-
"pyqgc>=1.0.0",
|
|
46
50
|
"pyunigps>=1.0.0",
|
|
47
51
|
]
|
|
48
52
|
|
|
@@ -50,7 +54,6 @@ dependencies = [
|
|
|
50
54
|
gnssstreamer = "pygnssutils.gnssstreamer_cli:main"
|
|
51
55
|
gnssserver = "pygnssutils.gnssserver_cli:main"
|
|
52
56
|
gnssntripclient = "pygnssutils.gnssntripclient_cli:main"
|
|
53
|
-
gnssmqttclient = "pygnssutils.gnssmqttclient_cli:main"
|
|
54
57
|
pyrinexconv = "pygnssutils.rinex_conv_cli:main"
|
|
55
58
|
|
|
56
59
|
[project.urls]
|
|
@@ -12,7 +12,6 @@ from pyubxutils.ubxsimulator import UBXSimulator
|
|
|
12
12
|
from pygnssutils._version import __version__
|
|
13
13
|
from pygnssutils.exceptions import GNSSError, GNSSStreamError, ParameterError
|
|
14
14
|
from pygnssutils.globals import *
|
|
15
|
-
from pygnssutils.gnssmqttclient import GNSSMQTTClient
|
|
16
15
|
from pygnssutils.gnssntripclient import GNSSNTRIPClient
|
|
17
16
|
from pygnssutils.gnssreader import (
|
|
18
17
|
NMEA_PROTOCOL,
|
|
@@ -26,7 +25,6 @@ from pygnssutils.gnssreader import (
|
|
|
26
25
|
from pygnssutils.gnssserver import GNSSSocketServer
|
|
27
26
|
from pygnssutils.gnssstreamer import GNSSStreamer
|
|
28
27
|
from pygnssutils.helpers import *
|
|
29
|
-
from pygnssutils.mqttmessage import *
|
|
30
28
|
from pygnssutils.rawnav import *
|
|
31
29
|
from pygnssutils.rinex_conv import RinexConverter
|
|
32
30
|
|
|
@@ -13,7 +13,7 @@ Returns both the raw binary data (as bytes) and the parsed data.
|
|
|
13
13
|
|
|
14
14
|
- 'protfilter' governs which protocols (NMEA, UBX, SBF, QGC, UNI or RTCM3) are processed.
|
|
15
15
|
- 'msgfilter' governs which individual message types are processed.
|
|
16
|
-
- `parsing` governs whether payloads are
|
|
16
|
+
- `parsing` governs whether individual payloads are parsed.
|
|
17
17
|
- 'quitonerror' governs how errors are handled.
|
|
18
18
|
- 'msgmode' indicates the type of UBX datastream (output GET, input SET, query POLL).
|
|
19
19
|
If msgmode is set to SETPOLL, input/query mode will be automatically detected by parser.
|
|
@@ -318,8 +318,7 @@ class GNSSReader:
|
|
|
318
318
|
|
|
319
319
|
raw_data = None
|
|
320
320
|
parsed_data = None
|
|
321
|
-
|
|
322
|
-
while parsing: # loop until end of valid message or EOF
|
|
321
|
+
while True: # loop until end of valid message or EOF
|
|
323
322
|
try:
|
|
324
323
|
|
|
325
324
|
raw_data = None
|
|
@@ -336,38 +335,34 @@ class GNSSReader:
|
|
|
336
335
|
# if protocol filter passes UBX, return message,
|
|
337
336
|
# otherwise discard and continue
|
|
338
337
|
if self._protfilter & UBX_PROTOCOL:
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
continue
|
|
338
|
+
break
|
|
339
|
+
continue
|
|
342
340
|
# if it's an NMEA message (b'\x24\x..)
|
|
343
|
-
|
|
341
|
+
if bytehdr in NMEA_HDR:
|
|
344
342
|
raw_data, parsed_data = self._parse_nmea(bytehdr)
|
|
345
343
|
# if protocol filter passes NMEA, return message,
|
|
346
344
|
# otherwise discard and continue
|
|
347
345
|
if self._protfilter & NMEA_PROTOCOL:
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
continue
|
|
346
|
+
break
|
|
347
|
+
continue
|
|
351
348
|
# if it's an SBF message (b'\x24\x40')
|
|
352
|
-
|
|
349
|
+
if bytehdr in SBF_HDR:
|
|
353
350
|
raw_data, parsed_data = self._parse_sbf(bytehdr)
|
|
354
351
|
# if protocol filter passes SBF, return message,
|
|
355
352
|
# otherwise discard and continue
|
|
356
353
|
if self._protfilter & SBF_PROTOCOL:
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
continue
|
|
354
|
+
break
|
|
355
|
+
continue
|
|
360
356
|
# if it's an QGCmessage (b'\x51\x47')
|
|
361
|
-
|
|
357
|
+
if bytehdr in QGC_HDR:
|
|
362
358
|
raw_data, parsed_data = self._parse_qgc(bytehdr)
|
|
363
359
|
# if protocol filter passes QGC, return message,
|
|
364
360
|
# otherwise discard and continue
|
|
365
361
|
if self._protfilter & QGC_PROTOCOL:
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
continue
|
|
362
|
+
break
|
|
363
|
+
continue
|
|
369
364
|
# if it's an UNImessage (b'\xaa\x44\xb5')
|
|
370
|
-
|
|
365
|
+
if bytehdr in UNI_HDR[:2]:
|
|
371
366
|
byte3 = self._read_bytes(1)
|
|
372
367
|
bytehdr += byte3
|
|
373
368
|
if bytehdr != UNI_HDR:
|
|
@@ -376,21 +371,18 @@ class GNSSReader:
|
|
|
376
371
|
# if protocol filter passes UNI, return message,
|
|
377
372
|
# otherwise discard and continue
|
|
378
373
|
if self._protfilter & UNI_PROTOCOL:
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
continue
|
|
374
|
+
break
|
|
375
|
+
continue
|
|
382
376
|
# if it's a RTCM3 message
|
|
383
377
|
# (byte1 = 0xd3; byte2 = 0b000000**)
|
|
384
|
-
|
|
378
|
+
if byte1 == b"\xd3" and (byte2[0] & ~0x03) == 0:
|
|
385
379
|
raw_data, parsed_data = self._parse_rtcm3(bytehdr)
|
|
386
380
|
# if protocol filter passes RTCM, return message,
|
|
387
381
|
# otherwise discard and continue
|
|
388
382
|
if self._protfilter & RTCM3_PROTOCOL:
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
else:
|
|
393
|
-
raise GNSSStreamError(f"Unknown protocol header {bytehdr}.")
|
|
383
|
+
break
|
|
384
|
+
continue
|
|
385
|
+
raise GNSSStreamError(f"Unknown protocol header {bytehdr}.")
|
|
394
386
|
|
|
395
387
|
except EOFError:
|
|
396
388
|
return (None, None)
|
|
@@ -17,7 +17,6 @@ Supported output channels:
|
|
|
17
17
|
Supported input channels:
|
|
18
18
|
- NTRIP RTCM client
|
|
19
19
|
- NTRIP SPARTN client
|
|
20
|
-
- MQTT SPARTN client
|
|
21
20
|
- serial stream
|
|
22
21
|
- file stream
|
|
23
22
|
|
|
@@ -57,7 +56,6 @@ from pygnssutils.globals import (
|
|
|
57
56
|
FORMAT_PARSED,
|
|
58
57
|
FORMAT_PARSEDSTRING,
|
|
59
58
|
INPUT_FILE,
|
|
60
|
-
INPUT_MQTT_SPARTN,
|
|
61
59
|
INPUT_NONE,
|
|
62
60
|
INPUT_NTRIP_RTCM,
|
|
63
61
|
INPUT_NTRIP_SPARTN,
|
|
@@ -73,7 +71,6 @@ from pygnssutils.globals import (
|
|
|
73
71
|
OUTPUT_TEXT_FILE,
|
|
74
72
|
UBXSIMULATOR,
|
|
75
73
|
)
|
|
76
|
-
from pygnssutils.gnssmqttclient import GNSSMQTTClient
|
|
77
74
|
from pygnssutils.gnssntripclient import GNSSNTRIPClient
|
|
78
75
|
from pygnssutils.gnssreader import (
|
|
79
76
|
ERR_LOG,
|
|
@@ -162,34 +159,6 @@ def _setup_input_ntrip(app: object, datatype: str, **kwargs) -> object:
|
|
|
162
159
|
return gnc
|
|
163
160
|
|
|
164
161
|
|
|
165
|
-
def _setup_input_mqtt(app: object, datatype: str, **kwargs) -> object:
|
|
166
|
-
"""
|
|
167
|
-
Set up MQTT SPARTN client as input data source.
|
|
168
|
-
|
|
169
|
-
:param app: calling application (i.e. gnssstreamer)
|
|
170
|
-
:param datatype: "MQTT"
|
|
171
|
-
:returns: reference to MQTT client
|
|
172
|
-
:rtype: GNSSMQTTClient
|
|
173
|
-
"""
|
|
174
|
-
|
|
175
|
-
# pylint: disable=unused-argument
|
|
176
|
-
|
|
177
|
-
prot, hostname, port, path = parse_url(kwargs["input"])
|
|
178
|
-
prot = 1 if prot == "https" else 0
|
|
179
|
-
|
|
180
|
-
gmq = GNSSMQTTClient(app)
|
|
181
|
-
gmq.start(
|
|
182
|
-
server=hostname,
|
|
183
|
-
port=port,
|
|
184
|
-
clientid=kwargs.get("rtkuser", "anon"),
|
|
185
|
-
region=path.lower(), # e.g. "eu"
|
|
186
|
-
mode=0, # IP (as opposed to 1 = L-Band)
|
|
187
|
-
output=kwargs["inqueue"], # send SPARTN data to receiver
|
|
188
|
-
)
|
|
189
|
-
|
|
190
|
-
return gmq
|
|
191
|
-
|
|
192
|
-
|
|
193
162
|
def _setup_input_stream(app: object, datatype: str, **kwargs) -> object:
|
|
194
163
|
"""
|
|
195
164
|
Set up serial stream as input data source.
|
|
@@ -379,8 +348,6 @@ def _run_streamer(stream, **kwargs):
|
|
|
379
348
|
_setup_input_ntrip(gns, "RTCM", **kwargs)
|
|
380
349
|
elif cliinput == INPUT_NTRIP_SPARTN:
|
|
381
350
|
_setup_input_ntrip(gns, "SPARTN", **kwargs)
|
|
382
|
-
elif cliinput == INPUT_MQTT_SPARTN:
|
|
383
|
-
_setup_input_mqtt(gns, "MQTT", **kwargs)
|
|
384
351
|
elif cliinput == INPUT_SERIAL:
|
|
385
352
|
_setup_input_stream(gns, "SERIAL", **kwargs)
|
|
386
353
|
elif cliinput == INPUT_FILE:
|
|
@@ -568,7 +535,6 @@ def main():
|
|
|
568
535
|
f"CLI input type {INPUT_NONE} = none, "
|
|
569
536
|
f"{INPUT_NTRIP_RTCM} = RTK NTRIP RTCM, "
|
|
570
537
|
f"{INPUT_NTRIP_SPARTN} = RTK NTRIP SPARTN, "
|
|
571
|
-
f"{INPUT_MQTT_SPARTN} = RTK MQTT SPARTN, "
|
|
572
538
|
f"{INPUT_SERIAL} = serial port, "
|
|
573
539
|
f"{INPUT_FILE} = binary file"
|
|
574
540
|
),
|
|
@@ -577,7 +543,6 @@ def main():
|
|
|
577
543
|
INPUT_NONE,
|
|
578
544
|
INPUT_NTRIP_RTCM,
|
|
579
545
|
INPUT_NTRIP_SPARTN,
|
|
580
|
-
INPUT_MQTT_SPARTN,
|
|
581
546
|
INPUT_SERIAL,
|
|
582
547
|
INPUT_FILE,
|
|
583
548
|
],
|
|
@@ -592,8 +557,6 @@ def main():
|
|
|
592
557
|
"(e.g. 'http://rtk2go.com:2101/MOUNTPOINT'); "
|
|
593
558
|
f"If cliinput = {INPUT_NTRIP_SPARTN}, format = full url "
|
|
594
559
|
"(e.g. 'https://ppntrip.services.u-blox.com:2102/EU'); "
|
|
595
|
-
f"If cliinput = {INPUT_MQTT_SPARTN}, format = full url "
|
|
596
|
-
"(e.g. 'https://pp.services.u-blox.com:8883/eu', where /path signifies region); "
|
|
597
560
|
f"If cliinput = {INPUT_SERIAL}, format = port@baudrate (e.g. '/dev/tty.ACM1@38400'); "
|
|
598
561
|
f"If cliinput = {INPUT_FILE}, format = file name (e.g. '/home/myuser/ubxconfig.ubx'). "
|
|
599
562
|
"NB: gnssstreamer will have exclusive use of any serial port."
|
|
@@ -1355,7 +1355,7 @@ def format_licenseofuse(lou: str = "") -> str:
|
|
|
1355
1355
|
|
|
1356
1356
|
if lou == "":
|
|
1357
1357
|
return ""
|
|
1358
|
-
return f"{
|
|
1358
|
+
return f"{lou:<{DATAWIDTH}}LICENSE OF USE\n"
|
|
1359
1359
|
|
|
1360
1360
|
|
|
1361
1361
|
def format_stationinfo(station: str = "") -> str:
|