From bada965bb51891600cb172adcdec7683ee22aaf0 Mon Sep 17 00:00:00 2001 From: semuadmin <28569967+semuadmin@users.noreply.github.com> Date: Fri, 12 Apr 2024 20:23:28 +0100 Subject: [PATCH 1/5] streamline socket-server --- .vscode/settings.json | 2 +- RELEASE_NOTES.md | 6 ++++++ pyproject.toml | 2 +- src/pygnssutils/_version.py | 2 +- src/pygnssutils/globals.py | 9 +++++++++ src/pygnssutils/socket_server.py | 26 ++++++-------------------- 6 files changed, 24 insertions(+), 23 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index b2d8713..a5bd168 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,5 @@ "editor.formatOnSave": true, "modulename": "${workspaceFolderBasename}", "distname": "${workspaceFolderBasename}", - "moduleversion": "1.0.24" + "moduleversion": "1.0.25" } \ No newline at end of file diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 9a33b2f..4ea82d2 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,11 @@ # pygnssutils Release Notes +### RELEASE 1.0.25 + +ENHANCEMENTS: + +1. Minor internal streamlining - no functional changes. + ### RELEASE 1.0.24 FIXES: diff --git a/pyproject.toml b/pyproject.toml index 2523482..de74621 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ name = "pygnssutils" authors = [{ name = "semuadmin", email = "semuadmin@semuconsulting.com" }] maintainers = [{ name = "semuadmin", email = "semuadmin@semuconsulting.com" }] description = "GNSS Command Line Utilities" -version = "1.0.24" +version = "1.0.25" license = { file = "LICENSE" } readme = "README.md" requires-python = ">=3.8" diff --git a/src/pygnssutils/_version.py b/src/pygnssutils/_version.py index e24e3a1..ece0789 100644 --- a/src/pygnssutils/_version.py +++ b/src/pygnssutils/_version.py @@ -8,4 +8,4 @@ :license: BSD 3-Clause """ -__version__ = "1.0.24" +__version__ = "1.0.25" diff --git a/src/pygnssutils/globals.py b/src/pygnssutils/globals.py index e29a4f4..184e177 100644 --- a/src/pygnssutils/globals.py +++ b/src/pygnssutils/globals.py @@ -95,3 +95,12 @@ (36.30, 128.20): "kr", (39.20, -096.60): "us", } + +HTTPCODES = { + 200: "OK", + 400: "Bad Request", + 401: "Unauthorized", + 403: "Forbidden", + 404: "Not Found", + 405: "Method Not Allowed", +} diff --git a/src/pygnssutils/socket_server.py b/src/pygnssutils/socket_server.py index e40ebc4..4e8d180 100644 --- a/src/pygnssutils/socket_server.py +++ b/src/pygnssutils/socket_server.py @@ -36,7 +36,7 @@ from threading import Event, Thread from pygnssutils._version import __version__ as VERSION -from pygnssutils.globals import CONNECTED, DISCONNECTED +from pygnssutils.globals import CONNECTED, DISCONNECTED, HTTPCODES from pygnssutils.helpers import ipprot2int # from pygpsclient import version as PYGPSVERSION @@ -280,17 +280,12 @@ def handle(self): if self.server.ntripmode: # NTRIP server mode self.data = self.request.recv(BUFSIZE) resptype, resp = self._process_ntrip_request(self.data) - if resptype == SRT: # sourcetable request - self.wfile.write(resp) - self.wfile.flush() - elif resptype == RTCM: # RTCM3 data request - self.wfile.write(resp) + if resptype is not None: + self.wfile.write(resp) # send HTTP response self.wfile.flush() + if resptype == RTCM: # RTCM3 data request while True: # send continuous RTCM data stream self._write_from_mq() - elif resptype == BAD: # unauthorised - self.wfile.write(resp) - self.wfile.flush() else: break @@ -345,7 +340,7 @@ def _process_ntrip_request(self, data: bytes) -> bytes: if validmp: # respond by opening RTCM3 stream http = self._format_data() return RTCM, bytes(http, "UTF-8") - return None + return None, None def _format_sourcetable(self) -> str: """ @@ -405,20 +400,11 @@ def _format_http_header(self, code: int = 200) -> str: :rtype: str """ - codes = { - 200: "OK", - 400: "Bad Request", - 401: "Unauthorized", - 403: "Forbidden", - 404: "Not Found", - 405: "Method Not Allowed", - } - dat = datetime.now(timezone.utc) server_date = dat.strftime("%d %b %Y") http_date = dat.strftime("%a, %d %b %Y %H:%M:%S %Z") header = ( - f"HTTP/1.1 {code} {codes[code]}\r\n" + f"HTTP/1.1 {code} {HTTPCODES[code]}\r\n" + "Ntrip-Version: Ntrip/2.0\r\n" + "Ntrip-Flags: \r\n" + f"Server: pygnssutils_NTRIP_Caster_{VERSION}/of:{server_date}\r\n" From 1654f718c50578ccc905dd1c9307c73c2cf05a4e Mon Sep 17 00:00:00 2001 From: semuadmin <28569967+semuadmin@users.noreply.github.com> Date: Fri, 19 Apr 2024 07:57:16 +0100 Subject: [PATCH 2/5] update min pyspartn ver to 0.3.0 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index de74621..514c5b6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,7 @@ dependencies = [ "certifi>=2024.0.0", "paho-mqtt>=1.6.0", "pyserial>=3.5", - "pyspartn>=0.2.1", + "pyspartn>=0.3.0", "pyubx2>=1.2.39", ] From 34c893e9eaa168f24ba89ddbddd869db3c2f3c95 Mon Sep 17 00:00:00 2001 From: semuadmin <28569967+semuadmin@users.noreply.github.com> Date: Tue, 23 Apr 2024 12:02:48 +0100 Subject: [PATCH 3/5] update min pyspartn version to 0.3.1 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 514c5b6..357767b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,7 @@ dependencies = [ "certifi>=2024.0.0", "paho-mqtt>=1.6.0", "pyserial>=3.5", - "pyspartn>=0.3.0", + "pyspartn>=0.3.1", "pyubx2>=1.2.39", ] From e328a6cae91870f95abaa71257fbb9879de906e1 Mon Sep 17 00:00:00 2001 From: semuadmin <28569967+semuadmin@users.noreply.github.com> Date: Thu, 25 Apr 2024 11:10:40 +0100 Subject: [PATCH 4/5] add decrypt option to gnssmqttclient --- RELEASE_NOTES.md | 3 +- examples/gnssmqttclient_example.py | 64 ++++++++++++++++++++++-------- src/pygnssutils/gnssmqttclient.py | 36 ++++++++++++++++- 3 files changed, 85 insertions(+), 18 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 4ea82d2..1d3b123 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -4,7 +4,8 @@ ENHANCEMENTS: -1. Minor internal streamlining - no functional changes. +1. Add SPARTN payload decrypt option to gnssnmqqclient. +1. Minor internal streamlining. ### RELEASE 1.0.24 diff --git a/examples/gnssmqttclient_example.py b/examples/gnssmqttclient_example.py index 7bf5980..904dedf 100644 --- a/examples/gnssmqttclient_example.py +++ b/examples/gnssmqttclient_example.py @@ -3,10 +3,15 @@ Illustration of GNSSMQTTClient class. -Reads selected topics from MQTT server and outputs raw data to log file. +Reads selected topics from MQTT server and outputs data to terminal or log file. -Expects user's Client ID to be set up in environment variable MQTTCLIENTID. -Expects user's *.crt and *.pem files to be placed in user's home directory. +- ClientID can be provided as keyword argument or set in environment variable MQTTCLIENTID. +- SPARTN decryption key can be provided as keyword argument or set in environment variable MQTTKEY. +- Expects user's *.crt and *.pem files to be placed in user's home directory. + +Usage: + + python3 gnssmqttclient_example.py clientid="your-client-id" outfile="spartn_ip.log" decode=1 decryptkey=yourkey decryptbasedate=yourbasedate Created on 5 Jun 2023 @@ -15,17 +20,33 @@ :license: BSD 3-Clause """ -from time import sleep -from threading import Event +from datetime import datetime from os import getenv, path from pathlib import Path -from pygnssutils import GNSSMQTTClient, SPARTN_PPSERVER, OUTPORT_SPARTN +from sys import argv +from threading import Event +from time import sleep + +from pygnssutils import OUTPORT_SPARTN, SPARTN_PPSERVER, GNSSMQTTClient -clientid = getenv("MQTTCLIENTID") # or hard code here -try: - with open("spartn_ip.log", "wb") as outfile: - kwargs = { +def main(**kwargs): + """ + Main routine. + """ + + clientid = kwargs.get("clientid", getenv("MQTTCLIENTID", default="enter-client-id")) + outfile = kwargs.get("outfile", None) + decode = kwargs.get("decode", 0) + decryptkey = kwargs.get("decryptkey", getenv("MQTTKEY", default=None)) + decryptbasedate = kwargs.get("decryptbasedate", datetime.now()) + stream = None + + if outfile is not None: + stream = open(outfile, "wb") + + try: + settings = { "server": SPARTN_PPSERVER, # Thingstream MQTT server "port": OUTPORT_SPARTN, # 8883 "clientid": clientid, @@ -35,16 +56,27 @@ "topic_ip": 1, # SPARTN correction data (SPARTN OCB, HPAC & GAD messages) "topic_mga": 0, # Assist Now ephemera data (UBX MGA-EPH-* messages) "topic_key": 0, # SPARTN decryption keys (UBX RXM_SPARTNKEY messages) - "output": outfile, + "decode": decode, + "decryptkey": decryptkey, + "decryptbasedate": decryptbasedate, + "output": stream, "errevent": Event(), } - with GNSSMQTTClient(None, **kwargs) as gsc: - streaming = gsc.start(**kwargs) + with GNSSMQTTClient(None, **settings) as gsc: + streaming = gsc.start(**settings) while ( - streaming and not kwargs["errevent"].is_set() + streaming and not settings["errevent"].is_set() ): # run until error or user presses CTRL-C sleep(3) sleep(3) -except (KeyboardInterrupt, TimeoutError): - gsc.stop() + except (KeyboardInterrupt, TimeoutError): + gsc.stop() + finally: + if outfile is not None: + stream.close() + + +if __name__ == "__main__": + + main(**dict(arg.split("=") for arg in argv[1:])) diff --git a/src/pygnssutils/gnssmqttclient.py b/src/pygnssutils/gnssmqttclient.py index 1aecbad..d764dbb 100644 --- a/src/pygnssutils/gnssmqttclient.py +++ b/src/pygnssutils/gnssmqttclient.py @@ -94,6 +94,9 @@ def __init__(self, app=None, **kwargs): "topic_key": 1, "tlscrt": path.join(Path.home(), f"device-{clientid}-pp-cert.crt"), "tlskey": path.join(Path.home(), f"device-{clientid}-pp-key.pem"), + "decode": 0, + "decryptkey": getenv("MQTTKEY", default=None), + "decryptbasedate": datetime.now(), "output": None, } @@ -171,6 +174,9 @@ def start(self, **kwargs) -> int: "topic_key", "tlscrt", "tlskey", + "decode", + "decryptkey", + "decryptbasedate", "output", ]: if kwarg in kwargs: @@ -251,6 +257,9 @@ def _run( "output": settings["output"], "topics": topics, "app": app, + "decode": settings["decode"], + "key": settings["decryptkey"], + "basedate": settings["decryptbasedate"], } try: @@ -392,7 +401,12 @@ def do_write(userdata: dict, raw: bytes, parsed: object): parsed = MQTTMessage(msg.topic, msg.payload) do_write(userdata, msg.payload, parsed) else: # SPARTN protocol message - spr = SPARTNReader(BytesIO(msg.payload)) + spr = SPARTNReader( + BytesIO(msg.payload), + decode=userdata["decode"], + key=userdata["key"], + basedate=userdata["basedate"], + ) try: for raw, parsed in spr: do_write(userdata, raw, parsed) @@ -554,6 +568,26 @@ def main(): help="Fully-qualified path to TLS key (*.pem)", default=path.join(Path.home(), f"device-{clientid}-pp-key.pem"), ) + ap.add_argument( + "--decode", + required=False, + help="Decode payload?", + type=int, + choices=[0, 1], + default=0, + ) + ap.add_argument( + "--decryptkey", + required=False, + help="Decryption key for encrypted payloads", + default=getenv("MQTTKEY", default=None), + ) + ap.add_argument( + "--decryptbasedate", + required=False, + help="Decryption basedate for encrypted payloads", + default=datetime.now(), + ) ap.add_argument( "--output", required=False, From 5af087c5c8adb6fe41480023edd9dec04eaa74c9 Mon Sep 17 00:00:00 2001 From: semuadmin <28569967+semuadmin@users.noreply.github.com> Date: Fri, 26 Apr 2024 08:26:02 +0100 Subject: [PATCH 5/5] update min pyspartn version to 0.3.2 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 357767b..fdc536f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,7 @@ dependencies = [ "certifi>=2024.0.0", "paho-mqtt>=1.6.0", "pyserial>=3.5", - "pyspartn>=0.3.1", + "pyspartn>=0.3.2", "pyubx2>=1.2.39", ]