not1mm 24.4.4__py3-none-any.whl → 24.4.8__py3-none-any.whl

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.
not1mm/__main__.py CHANGED
@@ -62,6 +62,7 @@ from not1mm.lib.select_contest import SelectContest
62
62
  from not1mm.lib.settings import Settings
63
63
  from not1mm.lib.version import __version__
64
64
  from not1mm.lib.versiontest import VersionTest
65
+ from not1mm.lib.ft8_watcher import FT8Watcher
65
66
 
66
67
  import not1mm.fsutils as fsutils
67
68
  from not1mm.logwindow import LogWindow
@@ -199,6 +200,8 @@ class MainWindow(QtWidgets.QMainWindow):
199
200
  self.leftdot.hide()
200
201
  self.rightdot.hide()
201
202
  self.n1mm = N1MM()
203
+ self.ft8 = FT8Watcher()
204
+ self.ft8.set_callback(self.ft8_result)
202
205
  self.mscp = SCP(fsutils.APP_DATA_PATH)
203
206
  self.next_field = self.other_2
204
207
  self.dupe_indicator.hide()
@@ -461,7 +464,7 @@ class MainWindow(QtWidgets.QMainWindow):
461
464
  }
462
465
 
463
466
  self.setWindowIcon(
464
- QtGui.QIcon(str(fsutils.APP_DATA_PATH / "k6gte.not1mm-64.png"))
467
+ QtGui.QIcon(str(fsutils.APP_DATA_PATH / "k6gte.not1mm-32.png"))
465
468
  )
466
469
  self.readpreferences()
467
470
  self.dbname = fsutils.USER_DATA_PATH / self.pref.get(
@@ -484,6 +487,40 @@ class MainWindow(QtWidgets.QMainWindow):
484
487
  if self.pref.get("contest"):
485
488
  self.load_contest()
486
489
 
490
+ self.actionLog_Window.setChecked(self.pref.get("logwindow", False))
491
+ if self.log_window:
492
+ self.log_window.close()
493
+ if self.actionLog_Window.isChecked():
494
+ self.log_window = LogWindow()
495
+ self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.log_window)
496
+ self.log_window.show()
497
+
498
+ self.actionBandmap.setChecked(self.pref.get("bandmapwindow", False))
499
+ if self.bandmap_window:
500
+ self.bandmap_window.close()
501
+ if self.actionBandmap.isChecked():
502
+ self.bandmap_window = BandMapWindow()
503
+ self.addDockWidget(
504
+ Qt.DockWidgetArea.RightDockWidgetArea, self.bandmap_window
505
+ )
506
+ self.bandmap_window.show()
507
+
508
+ self.actionCheck_Window.setChecked(self.pref.get("checkwindow", False))
509
+ if self.check_window:
510
+ self.check_window.close()
511
+ if self.actionCheck_Window.isChecked():
512
+ self.check_window = CheckWindow()
513
+ self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.check_window)
514
+ self.check_window.show()
515
+
516
+ self.actionVFO.setChecked(self.pref.get("vfowindow", False))
517
+ if self.vfo_window:
518
+ self.vfo_window.close()
519
+ if self.actionVFO.isChecked():
520
+ self.vfo_window = VfoWindow()
521
+ self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.vfo_window)
522
+ self.vfo_window.show()
523
+
487
524
  if not DEBUG_ENABLED:
488
525
  if VersionTest(__version__).test():
489
526
  self.show_message_box(
@@ -491,6 +528,33 @@ class MainWindow(QtWidgets.QMainWindow):
491
528
  "You can udate to the current version by using:\npip install -U not1mm"
492
529
  )
493
530
 
531
+ def ft8_result(self, result: dict):
532
+ """
533
+ Callback for ft8 watcher
534
+
535
+ {
536
+ 'CALL': 'KE0OG',
537
+ 'GRIDSQUARE': 'DM10AT',
538
+ 'MODE': 'FT8',
539
+ 'RST_SENT': '',
540
+ 'RST_RCVD': '',
541
+ 'QSO_DATE': '20210329',
542
+ 'TIME_ON': '183213',
543
+ 'QSO_DATE_OFF': '20210329',
544
+ 'TIME_OFF': '183213',
545
+ 'BAND': '20M',
546
+ 'FREQ': '14.074754',
547
+ 'STATION_CALLSIGN': 'K6GTE',
548
+ 'MY_GRIDSQUARE': 'DM13AT',
549
+ 'CONTEST_ID': 'ARRL-FIELD-DAY',
550
+ 'SRX_STRING': '1D UT',
551
+ 'CLASS': '1D',
552
+ 'ARRL_SECT': 'UT'
553
+ }
554
+
555
+ """
556
+ print(f"{result=}")
557
+
494
558
  def setDarkMode(self, dark):
495
559
  """testing"""
496
560
 
@@ -1389,35 +1453,49 @@ class MainWindow(QtWidgets.QMainWindow):
1389
1453
 
1390
1454
  def launch_log_window(self) -> None:
1391
1455
  """Launch the log window"""
1456
+ self.pref["logwindow"] = self.actionLog_Window.isChecked()
1457
+ self.write_preference()
1392
1458
  if self.log_window:
1393
1459
  self.log_window.close()
1394
- self.log_window = LogWindow()
1395
- self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.log_window)
1396
- self.log_window.show()
1460
+ if self.actionLog_Window.isChecked():
1461
+ self.log_window = LogWindow()
1462
+ self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.log_window)
1463
+ self.log_window.show()
1397
1464
 
1398
1465
  def launch_bandmap_window(self) -> None:
1399
1466
  """Launch the bandmap window"""
1467
+ self.pref["bandmapwindow"] = self.actionBandmap.isChecked()
1468
+ self.write_preference()
1400
1469
  if self.bandmap_window:
1401
1470
  self.bandmap_window.close()
1402
- self.bandmap_window = BandMapWindow()
1403
- self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.bandmap_window)
1404
- self.bandmap_window.show()
1471
+ if self.actionBandmap.isChecked():
1472
+ self.bandmap_window = BandMapWindow()
1473
+ self.addDockWidget(
1474
+ Qt.DockWidgetArea.RightDockWidgetArea, self.bandmap_window
1475
+ )
1476
+ self.bandmap_window.show()
1405
1477
 
1406
1478
  def launch_check_window(self) -> None:
1407
1479
  """Launch the check window"""
1480
+ self.pref["checkwindow"] = self.actionCheck_Window.isChecked()
1481
+ self.write_preference()
1408
1482
  if self.check_window:
1409
1483
  self.check_window.close()
1410
- self.check_window = CheckWindow()
1411
- self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.check_window)
1412
- self.check_window.show()
1484
+ if self.actionCheck_Window.isChecked():
1485
+ self.check_window = CheckWindow()
1486
+ self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.check_window)
1487
+ self.check_window.show()
1413
1488
 
1414
1489
  def launch_vfo(self) -> None:
1415
1490
  """Launch the VFO window"""
1491
+ self.pref["vfowindow"] = self.actionVFO.isChecked()
1492
+ self.write_preference()
1416
1493
  if self.vfo_window:
1417
1494
  self.vfo_window.close()
1418
- self.vfo_window = VfoWindow()
1419
- self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.vfo_window)
1420
- self.vfo_window.show()
1495
+ if self.actionVFO.isChecked():
1496
+ self.vfo_window = VfoWindow()
1497
+ self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.vfo_window)
1498
+ self.vfo_window.show()
1421
1499
 
1422
1500
  def clear_band_indicators(self) -> None:
1423
1501
  """
not1mm/data/main.ui CHANGED
@@ -894,7 +894,6 @@
894
894
  <item>
895
895
  <widget class="QFrame" name="Button_Row1">
896
896
  <layout class="QHBoxLayout" name="ButtonRow1">
897
-
898
897
  <property name="sizeConstraint">
899
898
  <enum>QLayout::SetNoConstraint</enum>
900
899
  </property>
@@ -1543,6 +1542,9 @@
1543
1542
  </property>
1544
1543
  </action>
1545
1544
  <action name="actionLog_Window">
1545
+ <property name="checkable">
1546
+ <bool>true</bool>
1547
+ </property>
1546
1548
  <property name="text">
1547
1549
  <string>QSO Log</string>
1548
1550
  </property>
@@ -1708,6 +1710,9 @@
1708
1710
  </property>
1709
1711
  </action>
1710
1712
  <action name="actionBandmap">
1713
+ <property name="checkable">
1714
+ <bool>true</bool>
1715
+ </property>
1711
1716
  <property name="text">
1712
1717
  <string>Bandmap</string>
1713
1718
  </property>
@@ -1743,11 +1748,17 @@
1743
1748
  </property>
1744
1749
  </action>
1745
1750
  <action name="actionCheck_Window">
1751
+ <property name="checkable">
1752
+ <bool>true</bool>
1753
+ </property>
1746
1754
  <property name="text">
1747
1755
  <string>Check Partial</string>
1748
1756
  </property>
1749
1757
  </action>
1750
1758
  <action name="actionVFO">
1759
+ <property name="checkable">
1760
+ <bool>true</bool>
1761
+ </property>
1751
1762
  <property name="text">
1752
1763
  <string>VFO</string>
1753
1764
  </property>
@@ -0,0 +1,132 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ WSJT-x UDP Packet Watcher
4
+ Email: michael.bridak@gmail.com
5
+ https://github.com/mbridak/not1mm
6
+ GPL V3
7
+ """
8
+
9
+ from PyQt6 import QtNetwork
10
+
11
+ # import struct
12
+
13
+
14
+ class FT8Watcher:
15
+ """Main Window"""
16
+
17
+ datadict = {}
18
+
19
+ def __init__(self, *args, **kwargs):
20
+ """Initialize"""
21
+ super().__init__(*args, **kwargs)
22
+ self.callback = None
23
+ self.udp_socket = QtNetwork.QUdpSocket()
24
+ self.udp_socket.bind(QtNetwork.QHostAddress.SpecialAddress.LocalHost, 2237)
25
+ self.udp_socket.readyRead.connect(self.on_udp_socket_ready_read)
26
+
27
+ def set_callback(self, callback):
28
+ """Set callback"""
29
+ self.callback = callback
30
+
31
+ @staticmethod
32
+ def getint(bytestring):
33
+ """
34
+ Returns an int from a bigendian signed 4 byte string
35
+ """
36
+ return int.from_bytes(bytestring, byteorder="big", signed=True)
37
+
38
+ @staticmethod
39
+ def getuint(bytestring):
40
+ """
41
+ Returns an int from a bigendian unsigned 4 byte string
42
+ """
43
+ return int.from_bytes(bytestring, byteorder="big", signed=False)
44
+
45
+ @staticmethod
46
+ def getbool(bytestring):
47
+ """
48
+ Returns a bool from a 1 byte string
49
+ """
50
+ return bool.from_bytes(bytestring, byteorder="big", signed=False)
51
+
52
+ def getvalue(self, item):
53
+ """I don't remember what this does."""
54
+ if item in self.datadict:
55
+ return self.datadict[item]
56
+ return "NOT_FOUND"
57
+
58
+ def on_udp_socket_ready_read(self):
59
+ """
60
+ This will process incomming UDP log packets from WSJT-X.
61
+ I Hope...
62
+ """
63
+ self.datadict = {}
64
+ datagram, sender_host, sender_port_number = self.udp_socket.readDatagram(
65
+ self.udp_socket.pendingDatagramSize()
66
+ )
67
+ # print("%s %s %s", sender_host, sender_port_number, datagram)
68
+
69
+ if datagram[0:4] != b"\xad\xbc\xcb\xda":
70
+ return # bail if no wsjt-x magic number
71
+ version = self.getuint(datagram[4:8])
72
+ packettype = self.getuint(datagram[8:12])
73
+ uniquesize = self.getint(datagram[12:16])
74
+ unique = datagram[16 : 16 + uniquesize].decode()
75
+ payload = datagram[16 + uniquesize :]
76
+
77
+ if packettype == 0: # Heartbeat
78
+ hbmaxschema = self.getuint(payload[0:4])
79
+ hbversion_len = self.getint(payload[4:8])
80
+ hbversion = payload[8 : 8 + hbversion_len].decode()
81
+ print(
82
+ f"heartbeat: sv:{version} p:{packettype} "
83
+ f"u:{unique}: ms:{hbmaxschema} av:{hbversion}"
84
+ )
85
+ return
86
+
87
+ if packettype == 1: # Status
88
+ ...
89
+ # [dialfreq] = struct.unpack(">Q", payload[0:8])
90
+ # modelen = self.getint(payload[8:12])
91
+ # mode = payload[12 : 12 + modelen].decode()
92
+ # payload = payload[12 + modelen :]
93
+ # dxcalllen = self.getint(payload[0:4])
94
+ # dxcall = payload[4 : 4 + dxcalllen].decode()
95
+ # print(
96
+ # "Status: sv:%s p:%s u:%s df:%s m:%s dxc:%s",
97
+ # version,
98
+ # packettype,
99
+ # unique,
100
+ # dialfreq,
101
+ # mode,
102
+ # dxcall,
103
+ # )
104
+
105
+ # if f"{dxcall}{self.band}{self.mode}" in self.dupdict:
106
+ # self.ft8dupe = f"{dxcall} {self.band}M {self.mode} FT8 Dupe!"
107
+ return
108
+
109
+ if packettype == 2: # Decode commented out because we really don't care
110
+ return
111
+
112
+ if packettype != 12:
113
+ return # bail if not logged ADIF
114
+ # if log packet it will contain this nugget.
115
+ gotcall = datagram.find(b"<call:")
116
+ if gotcall != -1:
117
+ datagram = datagram[gotcall:] # strip everything else
118
+ else:
119
+ return # Otherwise we don't want to bother with this packet
120
+
121
+ data = datagram.decode()
122
+ splitdata = data.upper().split("<")
123
+
124
+ for data in splitdata:
125
+ if data:
126
+ tag = data.split(":")
127
+ if tag == ["EOR>"]:
128
+ break
129
+ self.datadict[tag[0]] = tag[1].split(">")[1].strip()
130
+
131
+ if self.callback:
132
+ self.callback(self.datadict)
not1mm/lib/version.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """It's the version"""
2
2
 
3
- __version__ = "24.4.4"
3
+ __version__ = "24.4.8"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: not1mm
3
- Version: 24.4.4
3
+ Version: 24.4.8
4
4
  Summary: NOT1MM Logger
5
5
  Author-email: Michael Bridak <michael.bridak@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/mbridak/not1mm
@@ -177,6 +177,8 @@ I wish to thank those who've contributed to the project.
177
177
 
178
178
  ## Recent Changes
179
179
 
180
+ - [24-4-7] Added FT8Watcher class to prep for FT8 support.
181
+ - [24-4-4-1] Made docking widgets open state persistent.
180
182
  - [24-4-4] Added per-contest echange hint when adding new contest.
181
183
  - [24-4-2] Migrated to PyQt6. I'm sure there are broken things.
182
184
  - [24-4-1-2] Added color text indicators to the Check Partial window. Poached the code from @kyleboyle. Thanks! Fixed the Log, VFO and Check Partial windows to be actual docking widgets. Refocus call field after double clicking on item in the check partial window.
@@ -1,5 +1,5 @@
1
1
  not1mm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- not1mm/__main__.py,sha256=ofO8dhlMfS9G3ih_UEpxCCOWU1vmqMfH6CDCUqLbzOE,119858
2
+ not1mm/__main__.py,sha256=3Bjmi5rr_yuJHSdMNNc26skepG40crADyIppNqKUdu8,122807
3
3
  not1mm/bandmap.py,sha256=-wHbUmj-zqefyFO_ydLECwTtWcs37tSkA7Xm2zOVcLA,34318
4
4
  not1mm/checkwindow.py,sha256=ncIOZmuhM_eLR1gb-St8FqEefbUkD9p9VltFDJVxLeY,10465
5
5
  not1mm/fsutils.py,sha256=Li8Tq9K7c_q7onOHOQ7u1dOOFfhIIz5Aj2LKuQtGOO4,1652
@@ -26,7 +26,7 @@ not1mm/data/k6gte.not1mm-32.png,sha256=XdTsCa3xqwTfn26Ga7RwO_Vlbg_77RKkSc8bMxVcC
26
26
  not1mm/data/k6gte.not1mm-64.png,sha256=6ku45Gq1g5ezh04F07osoKRtanb3e4kbx5XdIEh3N90,2925
27
27
  not1mm/data/logwindow.ui,sha256=vfkNdzJgFs3tTOBKLDavF2zVMvNHWOZ82fAErRi6pQY,1436
28
28
  not1mm/data/logwindowx.ui,sha256=9FzDJtLRpagvAWcDjFdB9NnvNZ4bVxdTNHy1Jit2ido,1610
29
- not1mm/data/main.ui,sha256=X9sNqSZyKennX-7Ne4c8yLnkbN13T5YpDUeri-wPOn4,54070
29
+ not1mm/data/main.ui,sha256=imj6FbVeYxz90Z4MuTy730GFjpeT0OYs7TvzybmcSY8,54341
30
30
  not1mm/data/new_contest.ui,sha256=Xubngdbs_V_-o8huXzKOOaQOfj1NSXu9giIcaL4d0qk,21823
31
31
  not1mm/data/not1mm.html,sha256=c9-mfjMwDt4f5pySUruz2gREW33CQ2_rCddM2z5CZQo,23273
32
32
  not1mm/data/opon.ui,sha256=mC4OhoVIfR1H9IqHAKXliPMm8VOVmxSEadpsFQ7XnS4,2247
@@ -95,6 +95,7 @@ not1mm/lib/edit_contact.py,sha256=Ki9bGPpqyQQBB1cU8VIBDCal3lbXeQ6qxhzklmhE2_w,35
95
95
  not1mm/lib/edit_macro.py,sha256=raKWBwsHInj5EUKmvyLQ6gqc3ZFDlstsD3xqoM4PC8E,517
96
96
  not1mm/lib/edit_opon.py,sha256=j3qJ1aBsQoIOnQ9yiBl3lyeISvKTP0I_rtBYBPAfgeI,359
97
97
  not1mm/lib/edit_station.py,sha256=doL21Hs6jzIE43ohAopdFt_iqnRJZHFcqzcnCS0-iio,1965
98
+ not1mm/lib/ft8_watcher.py,sha256=rqvv7v2CXus0U8bekDenHvFVxFpYpzuApW-SA-SdtIA,4220
98
99
  not1mm/lib/ham_utility.py,sha256=pUrysod3wGk4BYOWDAKJxZZTiUNDE4ZzRk8S5ZnllNA,10978
99
100
  not1mm/lib/lookup.py,sha256=F2fl5QkMxaGSxl1XMWnLUub3T9Mt7LhCX4acOlAsks4,13952
100
101
  not1mm/lib/multicast.py,sha256=bnFUNHyy82GmIb3_88EPBVVssj7-HzkJPaH671cK8Qw,3249
@@ -104,7 +105,7 @@ not1mm/lib/plugin_common.py,sha256=AAKBPCXzTWZJb-h08uPNnHVG7bSCg7kwukc211gFivY,8
104
105
  not1mm/lib/select_contest.py,sha256=WsptLuwkouIHeocJL3oZ6-eUfEnhpwdc-x7eMZ_TIVM,359
105
106
  not1mm/lib/settings.py,sha256=tlXlJUUZP0IFwIDc9DboM5_1by_tHNtMXvyJ0E7B6RI,8877
106
107
  not1mm/lib/super_check_partial.py,sha256=p5l3u2ZOCBtlWgbvskC50FpuoaIpR07tfC6zTdRWbh4,2334
107
- not1mm/lib/version.py,sha256=HjO--fiMajqd0V_9fJOBO07Crj2XOf9gi0rZlRjUAi8,47
108
+ not1mm/lib/version.py,sha256=STPOMn2n-xW7ukFItJ4ju86aXQxaBtskG8gPdqediQk,47
108
109
  not1mm/lib/versiontest.py,sha256=8vDNptuBBunn-1IGkjNaquehqBYUJyjrPSF8Igmd4_Y,1286
109
110
  not1mm/plugins/10_10_fall_cw.py,sha256=fUjfwjuscDjicXIxsO0JHh7xTR9Vu0iPsrOLb896Qak,10873
110
111
  not1mm/plugins/10_10_spring_cw.py,sha256=WNaJP5mBQfaB6SxnFI0Vawt3AKDr94tKVtAK-EVhtUY,10878
@@ -138,9 +139,9 @@ not1mm/plugins/naqp_ssb.py,sha256=IWksulcb2_DxlkeW0h3048t8I-u00G_67KBVKkp-TV4,11
138
139
  not1mm/plugins/phone_weekly_test.py,sha256=gCX0ESUoiQzDp9puwibt9-dRembNsiuEeBdawCVvjHA,12316
139
140
  not1mm/plugins/stew_perry_topband.py,sha256=DIMI3mGMKokXXb9pPLqdhBI6JVnnIs7ZnAL23nFmshE,10588
140
141
  not1mm/plugins/winter_field_day.py,sha256=4rcfRtobwjHO6BNL3WOTHzBmyyeuX79BNGBG8PfjrI8,10238
141
- not1mm-24.4.4.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
142
- not1mm-24.4.4.dist-info/METADATA,sha256=w-lyauvXXE_ExubDbet2No9aXr7fuL_hsNe09gx1pBk,26634
143
- not1mm-24.4.4.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
144
- not1mm-24.4.4.dist-info/entry_points.txt,sha256=pMcZk_0dxFgLkcUkF0Q874ojpwOmF3OL6EKw9LgvocM,47
145
- not1mm-24.4.4.dist-info/top_level.txt,sha256=0YmTxEcDzQlzXub-lXASvoLpg_mt1c2thb5cVkDf5J4,7
146
- not1mm-24.4.4.dist-info/RECORD,,
142
+ not1mm-24.4.8.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
143
+ not1mm-24.4.8.dist-info/METADATA,sha256=J4EAMhz2Bh-79rMLBXavJhMr0LHDxf-otsgz--OL8Gg,26750
144
+ not1mm-24.4.8.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
145
+ not1mm-24.4.8.dist-info/entry_points.txt,sha256=pMcZk_0dxFgLkcUkF0Q874ojpwOmF3OL6EKw9LgvocM,47
146
+ not1mm-24.4.8.dist-info/top_level.txt,sha256=0YmTxEcDzQlzXub-lXASvoLpg_mt1c2thb5cVkDf5J4,7
147
+ not1mm-24.4.8.dist-info/RECORD,,