better timestamping and overhaul
This commit is contained in:
		
							
								
								
									
										76
									
								
								owrx/wsjt.py
									
									
									
									
									
								
							
							
						
						
									
										76
									
								
								owrx/wsjt.py
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| import threading | ||||
| import wave | ||||
| from datetime import datetime, timedelta, date | ||||
| from datetime import datetime, timedelta, date, timezone | ||||
| import time | ||||
| import sched | ||||
| import subprocess | ||||
| @@ -31,7 +31,7 @@ class WsjtChopper(threading.Thread): | ||||
|         filename = "{tmp_dir}/openwebrx-wsjtchopper-{id}-{timestamp}.wav".format( | ||||
|             tmp_dir = self.tmp_dir, | ||||
|             id = id(self), | ||||
|             timestamp = datetime.now().strftime("%Y%m%d-%H%M%S") | ||||
|             timestamp = datetime.utcnow().strftime(self.fileTimestampFormat) | ||||
|         ) | ||||
|         wavefile = wave.open(filename, "wb") | ||||
|         wavefile.setnchannels(1) | ||||
| @@ -71,9 +71,9 @@ class WsjtChopper(threading.Thread): | ||||
|         self._scheduleNextSwitch() | ||||
|  | ||||
|     def decoder_commandline(self, file): | ||||
|         ''' | ||||
|         """ | ||||
|         must be overridden in child classes | ||||
|         ''' | ||||
|         """ | ||||
|         return [] | ||||
|  | ||||
|     def decode(self): | ||||
| @@ -128,6 +128,7 @@ class WsjtChopper(threading.Thread): | ||||
| class Ft8Chopper(WsjtChopper): | ||||
|     def __init__(self, source): | ||||
|         self.interval = 15 | ||||
|         self.fileTimestampFormat = "%y%m%d_%H%M%S" | ||||
|         super().__init__(source) | ||||
|  | ||||
|     def decoder_commandline(self, file): | ||||
| @@ -138,6 +139,7 @@ class Ft8Chopper(WsjtChopper): | ||||
| class WsprChopper(WsjtChopper): | ||||
|     def __init__(self, source): | ||||
|         self.interval = 120 | ||||
|         self.fileTimestampFormat = "%y%m%d_%H%M" | ||||
|         super().__init__(source) | ||||
|  | ||||
|     def decoder_commandline(self, file): | ||||
| @@ -148,6 +150,7 @@ class WsprChopper(WsjtChopper): | ||||
| class Jt65Chopper(WsjtChopper): | ||||
|     def __init__(self, source): | ||||
|         self.interval = 60 | ||||
|         self.fileTimestampFormat = "%y%m%d_%H%M" | ||||
|         super().__init__(source) | ||||
|  | ||||
|     def decoder_commandline(self, file): | ||||
| @@ -158,6 +161,7 @@ class Jt65Chopper(WsjtChopper): | ||||
| class Jt9Chopper(WsjtChopper): | ||||
|     def __init__(self, source): | ||||
|         self.interval = 60 | ||||
|         self.fileTimestampFormat = "%y%m%d_%H%M" | ||||
|         super().__init__(source) | ||||
|  | ||||
|     def decoder_commandline(self, file): | ||||
| @@ -167,8 +171,6 @@ class Jt9Chopper(WsjtChopper): | ||||
|  | ||||
| class WsjtParser(object): | ||||
|     locator_pattern = re.compile(".*\\s([A-Z0-9]+)\\s([A-R]{2}[0-9]{2})$") | ||||
|     jt9_pattern = re.compile("^([0-9]{6}|\\*{4}) .*") | ||||
|     wspr_pattern = re.compile("^[0-9]{4} .*") | ||||
|     wspr_splitter_pattern = re.compile("([A-Z0-9]*)\\s([A-R]{2}[0-9]{2})\\s([0-9]+)") | ||||
|  | ||||
|     def __init__(self, handler): | ||||
| @@ -191,38 +193,45 @@ class WsjtParser(object): | ||||
|             if msg.startswith(" EOF on input file"): | ||||
|                 return | ||||
|  | ||||
|             out = {} | ||||
|             if WsjtParser.jt9_pattern.match(msg): | ||||
|             modes = list(WsjtParser.modes.keys()) | ||||
|             if msg[21] in modes or msg[19] in modes: | ||||
|                 out = self.parse_from_jt9(msg) | ||||
|             elif WsjtParser.wspr_pattern.match(msg): | ||||
|             else: | ||||
|                 out = self.parse_from_wsprd(msg) | ||||
|  | ||||
|             self.handler.write_wsjt_message(out) | ||||
|         except ValueError: | ||||
|             logger.exception("error while parsing wsjt message") | ||||
|  | ||||
|     def parse_timestamp(self, instring, dateformat): | ||||
|         ts = datetime.strptime(instring, dateformat).replace(tzinfo=timezone.utc) | ||||
|         return int(datetime.combine(date.today(), ts.time(), timezone.utc).timestamp() * 1000) | ||||
|  | ||||
|     def parse_from_jt9(self, msg): | ||||
|         # ft8 sample | ||||
|         # '222100 -15 -0.0  508 ~  CQ EA7MJ IM66' | ||||
|         # jt65 sample | ||||
|         # '**** -10  0.4 1556 #  CQ RN6AM KN95' | ||||
|         out = {} | ||||
|         if msg.startswith("****"): | ||||
|             out["timestamp"] = int(datetime.now().timestamp() * 1000) | ||||
|             msg = msg[5:] | ||||
|         # '2352  -7  0.4 1801 #  R0WAS R2ABM KO85' | ||||
|         # '0003  -4  0.4 1762 #  CQ R2ABM KO85' | ||||
|         modes = list(WsjtParser.modes.keys()) | ||||
|         if msg[19] in modes: | ||||
|             dateformat = "%H%M" | ||||
|         else: | ||||
|             ts = datetime.strptime(msg[0:6], "%H%M%S") | ||||
|             out["timestamp"] = int(datetime.combine(date.today(), ts.time(), datetime.now().tzinfo).timestamp() * 1000) | ||||
|             msg = msg[7:] | ||||
|         out["db"] = float(msg[0:3]) | ||||
|         out["dt"] = float(msg[4:8]) | ||||
|         out["freq"] = int(msg[9:13]) | ||||
|             dateformat = "%H%M%S" | ||||
|         timestamp = self.parse_timestamp(msg[0:len(dateformat)], dateformat) | ||||
|         msg = msg[len(dateformat) + 1:] | ||||
|         modeChar = msg[14:15] | ||||
|         out["mode"] = mode = WsjtParser.modes[modeChar] if modeChar in WsjtParser.modes else "unknown" | ||||
|         mode = WsjtParser.modes[modeChar] if modeChar in WsjtParser.modes else "unknown" | ||||
|         wsjt_msg = msg[17:53].strip() | ||||
|         self.parseLocator(wsjt_msg, mode) | ||||
|         out["msg"] = wsjt_msg | ||||
|         return out | ||||
|         return { | ||||
|             "timestamp": timestamp, | ||||
|             "db": float(msg[0:3]), | ||||
|             "dt": float(msg[4:8]), | ||||
|             "freq": int(msg[9:13]), | ||||
|             "mode": mode, | ||||
|             "msg": wsjt_msg | ||||
|         } | ||||
|  | ||||
|     def parseLocator(self, msg, mode): | ||||
|         m = WsjtParser.locator_pattern.match(msg) | ||||
| @@ -237,19 +246,18 @@ class WsjtParser(object): | ||||
|     def parse_from_wsprd(self, msg): | ||||
|         # wspr sample | ||||
|         # '2600 -24  0.4   0.001492 -1  G8AXA JO01 33' | ||||
|         out = {} | ||||
|         now = datetime.now() | ||||
|         ts = datetime.strptime(msg[0:4], "%M%S").replace(hour=now.hour) | ||||
|         out["timestamp"] = int(datetime.combine(date.today(), ts.time(), now.tzinfo).timestamp() * 1000) | ||||
|         out["db"] = float(msg[5:8]) | ||||
|         out["dt"] = float(msg[9:13]) | ||||
|         out["freq"] = float(msg[14:24]) | ||||
|         out["drift"] = int(msg[25:28]) | ||||
|         out["mode"] = "WSPR" | ||||
|         # '0052 -29  2.6   0.001486  0  G02CWT IO92 23' | ||||
|         wsjt_msg = msg[29:].strip() | ||||
|         out["msg"] = wsjt_msg | ||||
|         self.parseWsprMessage(wsjt_msg) | ||||
|         return out | ||||
|         return { | ||||
|             "timestamp": self.parse_timestamp(msg[0:4], "%H%M"), | ||||
|             "db": float(msg[5:8]), | ||||
|             "dt": float(msg[9:13]), | ||||
|             "freq": float(msg[14:24]), | ||||
|             "drift": int(msg[25:28]), | ||||
|             "mode": "WSPR", | ||||
|             "msg": wsjt_msg | ||||
|         } | ||||
|  | ||||
|     def parseWsprMessage(self, msg): | ||||
|         m = WsjtParser.wspr_splitter_pattern.match(msg) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jakob Ketterl
					Jakob Ketterl