not1mm 24.9.5__tar.gz → 24.9.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.
Files changed (163) hide show
  1. {not1mm-24.9.5 → not1mm-24.9.8}/PKG-INFO +19 -8
  2. {not1mm-24.9.5 → not1mm-24.9.8}/README.md +18 -7
  3. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/__main__.py +15 -8
  4. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/new_contest.ui +6 -1
  5. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/lib/database.py +2 -2
  6. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/lib/plugin_common.py +1 -1
  7. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/lib/version.py +1 -1
  8. not1mm-24.9.8/not1mm/plugins/weekly_rtty.py +442 -0
  9. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm.egg-info/PKG-INFO +19 -8
  10. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm.egg-info/SOURCES.txt +1 -0
  11. {not1mm-24.9.5 → not1mm-24.9.8}/pyproject.toml +1 -1
  12. {not1mm-24.9.5 → not1mm-24.9.8}/LICENSE +0 -0
  13. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/__init__.py +0 -0
  14. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/bandmap.py +0 -0
  15. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/checkwindow.py +0 -0
  16. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/JetBrainsMono-Regular.ttf +0 -0
  17. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/MASTER.SCP +0 -0
  18. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/about.ui +0 -0
  19. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/alpha bravo charlie delta.txt +0 -0
  20. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/bandmap.ui +0 -0
  21. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/check.png +0 -0
  22. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/checkwindow.ui +0 -0
  23. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/configuration.ui +0 -0
  24. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/contests.sql +0 -0
  25. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/cty.json +0 -0
  26. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/cwmacros.txt +0 -0
  27. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/donors.html +0 -0
  28. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/editcontact.ui +0 -0
  29. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/editmacro.ui +0 -0
  30. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/greendot.png +0 -0
  31. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/k6gte-not1mm.desktop +0 -0
  32. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/k6gte.not1mm-128.png +0 -0
  33. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/k6gte.not1mm-32.png +0 -0
  34. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/k6gte.not1mm-64.png +0 -0
  35. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/logwindow.ui +0 -0
  36. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/logwindowx.ui +0 -0
  37. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/main.ui +0 -0
  38. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/not1mm.html +0 -0
  39. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/opon.ui +0 -0
  40. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/0.wav +0 -0
  41. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/1.wav +0 -0
  42. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/2.wav +0 -0
  43. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/3.wav +0 -0
  44. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/4.wav +0 -0
  45. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/5.wav +0 -0
  46. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/6.wav +0 -0
  47. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/7.wav +0 -0
  48. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/73.wav +0 -0
  49. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/8.wav +0 -0
  50. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/9.wav +0 -0
  51. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/a.wav +0 -0
  52. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/again.wav +0 -0
  53. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/b.wav +0 -0
  54. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/c.wav +0 -0
  55. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/contest.wav +0 -0
  56. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/cq.wav +0 -0
  57. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/d.wav +0 -0
  58. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/e.wav +0 -0
  59. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/f.wav +0 -0
  60. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/g.wav +0 -0
  61. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/h.wav +0 -0
  62. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/i.wav +0 -0
  63. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/j.wav +0 -0
  64. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/k.wav +0 -0
  65. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/k6gte.wav +0 -0
  66. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/l.wav +0 -0
  67. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/m.wav +0 -0
  68. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/mynumber.wav +0 -0
  69. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/n.wav +0 -0
  70. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/nil.wav +0 -0
  71. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/o.wav +0 -0
  72. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/p.wav +0 -0
  73. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/q.wav +0 -0
  74. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/r.wav +0 -0
  75. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/roger.wav +0 -0
  76. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/s.wav +0 -0
  77. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/space.wav +0 -0
  78. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/t.wav +0 -0
  79. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/thankyou.wav +0 -0
  80. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/thankyouqrz.wav +0 -0
  81. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/u.wav +0 -0
  82. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/v.wav +0 -0
  83. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/w.wav +0 -0
  84. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/x.wav +0 -0
  85. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/y.wav +0 -0
  86. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/yourcall.wav +0 -0
  87. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/phonetics/z.wav +0 -0
  88. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/pickcontest.ui +0 -0
  89. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/radio_green.png +0 -0
  90. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/radio_grey.png +0 -0
  91. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/radio_red.png +0 -0
  92. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/reddot.png +0 -0
  93. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/settings.ui +0 -0
  94. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/splash.png +0 -0
  95. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/ssbmacros.txt +0 -0
  96. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/data/vfo.ui +0 -0
  97. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/fsutils.py +0 -0
  98. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/lib/__init__.py +0 -0
  99. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/lib/about.py +0 -0
  100. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/lib/cat_interface.py +0 -0
  101. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/lib/cwinterface.py +0 -0
  102. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/lib/edit_contact.py +0 -0
  103. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/lib/edit_macro.py +0 -0
  104. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/lib/edit_opon.py +0 -0
  105. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/lib/edit_station.py +0 -0
  106. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/lib/fldigi_watcher.py +0 -0
  107. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/lib/ft8_watcher.py +0 -0
  108. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/lib/ham_utility.py +0 -0
  109. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/lib/lookup.py +0 -0
  110. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/lib/multicast.py +0 -0
  111. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/lib/n1mm.py +0 -0
  112. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/lib/new_contest.py +0 -0
  113. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/lib/playsound.py +0 -0
  114. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/lib/select_contest.py +0 -0
  115. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/lib/settings.py +0 -0
  116. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/lib/super_check_partial.py +0 -0
  117. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/lib/versiontest.py +0 -0
  118. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/logwindow.py +0 -0
  119. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/10_10_fall_cw.py +0 -0
  120. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/10_10_spring_cw.py +0 -0
  121. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/10_10_summer_phone.py +0 -0
  122. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/10_10_winter_phone.py +0 -0
  123. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/__init__.py +0 -0
  124. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/arrl_10m.py +0 -0
  125. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/arrl_dx_cw.py +0 -0
  126. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/arrl_dx_ssb.py +0 -0
  127. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/arrl_field_day.py +0 -0
  128. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/arrl_rtty_ru.py +0 -0
  129. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/arrl_ss_cw.py +0 -0
  130. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/arrl_ss_phone.py +0 -0
  131. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/arrl_vhf_jan.py +0 -0
  132. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/arrl_vhf_jun.py +0 -0
  133. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/arrl_vhf_sep.py +0 -0
  134. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/canada_day.py +0 -0
  135. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/cq_160_cw.py +0 -0
  136. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/cq_160_ssb.py +0 -0
  137. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/cq_wpx_cw.py +0 -0
  138. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/cq_wpx_ssb.py +0 -0
  139. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/cq_ww_cw.py +0 -0
  140. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/cq_ww_ssb.py +0 -0
  141. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/cwt.py +0 -0
  142. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/general_logging.py +0 -0
  143. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/helvetia.py +0 -0
  144. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/iaru_hf.py +0 -0
  145. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/icwc_mst.py +0 -0
  146. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/jidx_cw.py +0 -0
  147. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/jidx_ph.py +0 -0
  148. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/k1usn_sst.py +0 -0
  149. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/naqp_cw.py +0 -0
  150. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/naqp_ssb.py +0 -0
  151. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/phone_weekly_test.py +0 -0
  152. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/ref_cw.py +0 -0
  153. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/stew_perry_topband.py +0 -0
  154. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/plugins/winter_field_day.py +0 -0
  155. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/radio.py +0 -0
  156. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/test.py +0 -0
  157. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/vfo.py +0 -0
  158. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm/voice_keying.py +0 -0
  159. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm.egg-info/dependency_links.txt +0 -0
  160. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm.egg-info/entry_points.txt +0 -0
  161. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm.egg-info/requires.txt +0 -0
  162. {not1mm-24.9.5 → not1mm-24.9.8}/not1mm.egg-info/top_level.txt +0 -0
  163. {not1mm-24.9.5 → not1mm-24.9.8}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: not1mm
3
- Version: 24.9.5
3
+ Version: 24.9.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
@@ -100,7 +100,7 @@ Requires-Dist: Levenshtein
100
100
  - [Cluster](#cluster)
101
101
  - [N1MM Packets](#n1mm-packets)
102
102
  - [Bands](#bands)
103
- - [Logging WSJT-X FT8/FT4 contacts](#logging-wsjt-x-ft8ft4-contacts)
103
+ - [Logging WSJT-X FT8/FT4 and FLDIGI RTTY contacts](#logging-wsjt-x-ft8ft4-and-fldigi-rtty-contacts)
104
104
  - [Sending CW](#sending-cw)
105
105
  - [Editing macro keys](#editing-macro-keys)
106
106
  - [Macro substitutions](#macro-substitutions)
@@ -169,9 +169,9 @@ when the program craps the bed. I'm only one guy, so if you see a bug let me kno
169
169
 
170
170
  ### Data and RTTY
171
171
 
172
- I don't do much of any digital or RTTY operating. This is why you don't see RTTY in
173
- the list of working contests. The Lord helps those who burn people at the... I
174
- mean, who help themselves. Feel free to fill in that hole with a pull request.
172
+ I've recently added portions of code to watch for WSTJ-X and fldigi QSOs. I've added
173
+ the Weekly RTTY Test, So RTTY could be tested. Also added FT8/4 and RTTY to ARRL Field
174
+ Day. Praying that it works. I'll add more details later.
175
175
 
176
176
  ### Other not so supported contests
177
177
 
@@ -222,10 +222,13 @@ generated, 'cause I'm lazy, list of those who've submitted PR's.
222
222
  - Phone Weekly Test
223
223
  - RAC Canada Day
224
224
  - Stew Perry Topband
225
+ - Weekly RTTY
225
226
  - Winter Field Day
226
227
 
227
228
  ## Recent Changes
228
229
 
230
+ - [24-9-8] Correct n1mm contact packet info.
231
+ - [24-9-6] Added the Weekly RTTY
229
232
  - [24-9-5] Added FlDigi support for Field Day.
230
233
  - [24-9-3] Added WSJT-X FT8 mode contacts to ARRL Field Day.
231
234
 
@@ -604,12 +607,20 @@ appear. Those without will not.
604
607
 
605
608
  ![Bands Configuration Screen](https://github.com/mbridak/not1mm/raw/master/pic/configure_bands.png)
606
609
 
607
- ## Logging WSJT-X FT8/FT4 contacts
610
+ ## Logging WSJT-X FT8/FT4 and FLDIGI RTTY contacts
608
611
 
609
- **Currently only working for ARRL Field Day.**
612
+ **FT8/FT4 Currently only working for ARRL Field Day.**
610
613
 
611
614
  not1mm listens for WSJT-X UDP traffic on the default localhost:2237. No setup is
612
- needed to be done on not1mm's side.
615
+ needed to be done on not1mm's side. That's good because I'm lazy.
616
+
617
+ not1mm polls for fldigi QSOs via it's XMLRPC interface. It does this in a rather stupid
618
+ way. It just keeps asking what was the last QSO and compares it to the previous response.
619
+ If it's different, it's new. I've added the Weekly RTTY Test so this can be tested.
620
+
621
+ Unlike WSJT, fldigi needs to be setup for this to work. The XMLRPC interface needs to be
622
+ active. And in fldigi's config dialog go to CONTESTS -> General -> CONTEST and select
623
+ Generic Contest. Make sure the Text Capture Order field says CALL EXCHANGE.
613
624
 
614
625
  ## Sending CW
615
626
 
@@ -69,7 +69,7 @@
69
69
  - [Cluster](#cluster)
70
70
  - [N1MM Packets](#n1mm-packets)
71
71
  - [Bands](#bands)
72
- - [Logging WSJT-X FT8/FT4 contacts](#logging-wsjt-x-ft8ft4-contacts)
72
+ - [Logging WSJT-X FT8/FT4 and FLDIGI RTTY contacts](#logging-wsjt-x-ft8ft4-and-fldigi-rtty-contacts)
73
73
  - [Sending CW](#sending-cw)
74
74
  - [Editing macro keys](#editing-macro-keys)
75
75
  - [Macro substitutions](#macro-substitutions)
@@ -138,9 +138,9 @@ when the program craps the bed. I'm only one guy, so if you see a bug let me kno
138
138
 
139
139
  ### Data and RTTY
140
140
 
141
- I don't do much of any digital or RTTY operating. This is why you don't see RTTY in
142
- the list of working contests. The Lord helps those who burn people at the... I
143
- mean, who help themselves. Feel free to fill in that hole with a pull request.
141
+ I've recently added portions of code to watch for WSTJ-X and fldigi QSOs. I've added
142
+ the Weekly RTTY Test, So RTTY could be tested. Also added FT8/4 and RTTY to ARRL Field
143
+ Day. Praying that it works. I'll add more details later.
144
144
 
145
145
  ### Other not so supported contests
146
146
 
@@ -191,10 +191,13 @@ generated, 'cause I'm lazy, list of those who've submitted PR's.
191
191
  - Phone Weekly Test
192
192
  - RAC Canada Day
193
193
  - Stew Perry Topband
194
+ - Weekly RTTY
194
195
  - Winter Field Day
195
196
 
196
197
  ## Recent Changes
197
198
 
199
+ - [24-9-8] Correct n1mm contact packet info.
200
+ - [24-9-6] Added the Weekly RTTY
198
201
  - [24-9-5] Added FlDigi support for Field Day.
199
202
  - [24-9-3] Added WSJT-X FT8 mode contacts to ARRL Field Day.
200
203
 
@@ -573,12 +576,20 @@ appear. Those without will not.
573
576
 
574
577
  ![Bands Configuration Screen](https://github.com/mbridak/not1mm/raw/master/pic/configure_bands.png)
575
578
 
576
- ## Logging WSJT-X FT8/FT4 contacts
579
+ ## Logging WSJT-X FT8/FT4 and FLDIGI RTTY contacts
577
580
 
578
- **Currently only working for ARRL Field Day.**
581
+ **FT8/FT4 Currently only working for ARRL Field Day.**
579
582
 
580
583
  not1mm listens for WSJT-X UDP traffic on the default localhost:2237. No setup is
581
- needed to be done on not1mm's side.
584
+ needed to be done on not1mm's side. That's good because I'm lazy.
585
+
586
+ not1mm polls for fldigi QSOs via it's XMLRPC interface. It does this in a rather stupid
587
+ way. It just keeps asking what was the last QSO and compares it to the previous response.
588
+ If it's different, it's new. I've added the Weekly RTTY Test so this can be tested.
589
+
590
+ Unlike WSJT, fldigi needs to be setup for this to work. The XMLRPC interface needs to be
591
+ active. And in fldigi's config dialog go to CONTESTS -> General -> CONTEST and select
592
+ Generic Contest. Make sure the Text Capture Order field says CALL EXCHANGE.
582
593
 
583
594
  ## Sending CW
584
595
 
@@ -1936,7 +1936,7 @@ class MainWindow(QtWidgets.QMainWindow):
1936
1936
  " "
1937
1937
  )[:19]
1938
1938
  self.contact["Call"] = self.callsign.text()
1939
- if self.contact.get("Mode") not in ("FT8", "FT4"):
1939
+ if self.contact.get("Mode") not in ("FT8", "FT4", "RTTY"):
1940
1940
  self.contact["Freq"] = round(
1941
1941
  float(self.radio_state.get("vfoa", 0.0)) / 1000, 2
1942
1942
  )
@@ -3214,14 +3214,21 @@ class MainWindow(QtWidgets.QMainWindow):
3214
3214
  cmd["bw"] = bw
3215
3215
  self.multicast_interface.send_as_json(cmd)
3216
3216
  if self.n1mm:
3217
+ self.n1mm.radio_info["Freq"] = vfo[:-1]
3218
+ self.n1mm.radio_info["TXFreq"] = vfo[:-1]
3219
+ self.n1mm.radio_info["Mode"] = mode
3220
+ self.n1mm.radio_info["OpCall"] = self.current_op
3221
+ self.n1mm.radio_info["IsRunning"] = str(
3222
+ self.pref.get("run_state", False)
3223
+ )
3217
3224
  if self.n1mm.send_radio_packets:
3218
- self.n1mm.radio_info["Freq"] = vfo[:-1]
3219
- self.n1mm.radio_info["TXFreq"] = vfo[:-1]
3220
- self.n1mm.radio_info["Mode"] = mode
3221
- self.n1mm.radio_info["OpCall"] = self.current_op
3222
- self.n1mm.radio_info["IsRunning"] = str(
3223
- self.pref.get("run_state", False)
3224
- )
3225
+ # self.n1mm.radio_info["Freq"] = vfo[:-1]
3226
+ # self.n1mm.radio_info["TXFreq"] = vfo[:-1]
3227
+ # self.n1mm.radio_info["Mode"] = mode
3228
+ # self.n1mm.radio_info["OpCall"] = self.current_op
3229
+ # self.n1mm.radio_info["IsRunning"] = str(
3230
+ # self.pref.get("run_state", False)
3231
+ # )
3225
3232
  self.n1mm.send_radio()
3226
3233
  except TypeError as err:
3227
3234
  logger.debug(f"{err=} {vfo=} {the_dict=}")
@@ -347,6 +347,11 @@
347
347
  <string>STEW PERRY TOPBAND</string>
348
348
  </property>
349
349
  </item>
350
+ <item>
351
+ <property name="text">
352
+ <string>WEEKLY RTTY</string>
353
+ </property>
354
+ </item>
350
355
  <item>
351
356
  <property name="text">
352
357
  <string>WINTER FIELD DAY</string>
@@ -841,7 +846,7 @@
841
846
  <enum>Qt::Horizontal</enum>
842
847
  </property>
843
848
  <property name="standardButtons">
844
- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
849
+ <set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
845
850
  </property>
846
851
  <property name="centerButtons">
847
852
  <bool>true</bool>
@@ -663,8 +663,8 @@ class DataBase:
663
663
  logger.debug("%s", exception)
664
664
  return {}
665
665
 
666
- def fetch_call_exists(self, call) -> dict:
667
- """returns a dict key of nr_count"""
666
+ def fetch_call_exists(self, call: str) -> dict:
667
+ """returns a dict key of call_count"""
668
668
  try:
669
669
  with sqlite3.connect(self.database) as conn:
670
670
  conn.row_factory = self.row_factory
@@ -172,7 +172,7 @@ def gen_adif(self, cabrillo_name: str, contest_id=""):
172
172
  file=file_descriptor,
173
173
  )
174
174
  # ------------CQ 160---------------
175
- elif cabrillo_name in ("CQ-160-CW", "CQ-160-SSB"):
175
+ elif cabrillo_name in ("CQ-160-CW", "CQ-160-SSB", "WEEKLY-RTTY"):
176
176
  rcv = f"{contact.get('Exchange1', '')}"
177
177
  if len(rcv) > 1:
178
178
  print(
@@ -1,3 +1,3 @@
1
1
  """It's the version"""
2
2
 
3
- __version__ = "24.9.5"
3
+ __version__ = "24.9.8"
@@ -0,0 +1,442 @@
1
+ """Weekly RTTY Test"""
2
+
3
+ # Geographic Focus: North America
4
+ # Participation: Worldwide
5
+ # Mode: RTTY
6
+ # Bands: 80, 40, 20, 15, 10m
7
+ # Classes: Single-Op (QRP/Low)
8
+ # Max power: LP: 100 watts
9
+ # QRP: 5 watts
10
+ # Exchange: Name + (state/province/country)
11
+ # Work stations: Once per band
12
+ # QSO Points: 1 point per QSO
13
+ # Multipliers: Each callsign once
14
+ # Score Calculation: Total score = total QSO points x total mults
15
+ # Submit logs by: September 8, 2024
16
+ # E-mail logs to: (none)
17
+ # Post log summary at: http://www.3830scores.com/
18
+ # Mail logs to: (none)
19
+ # Find rules at: https://radiosport.world/wrt.html
20
+
21
+ import datetime
22
+ import logging
23
+ import platform
24
+
25
+ from pathlib import Path
26
+
27
+ from PyQt6 import QtWidgets
28
+
29
+ from not1mm.lib.ham_utility import get_logged_band
30
+ from not1mm.lib.plugin_common import gen_adif, get_points
31
+ from not1mm.lib.version import __version__
32
+
33
+ logger = logging.getLogger(__name__)
34
+
35
+ ALTEREGO = None
36
+
37
+ EXCHANGE_HINT = "Name + SPC"
38
+
39
+ name = "WEEKLY RTTY TEST"
40
+ cabrillo_name = "WEEKLY-RTTY"
41
+ mode = "RTTY" # CW SSB BOTH RTTY
42
+ # columns = [0, 1, 2, 3, 4, 10, 11, 14, 15]
43
+ columns = [
44
+ "YYYY-MM-DD HH:MM:SS",
45
+ "Call",
46
+ "Freq",
47
+ "Exchange1",
48
+ "M1",
49
+ "PTS",
50
+ ]
51
+
52
+ advance_on_space = [True, True, True, True, True]
53
+
54
+ # 1 once per contest, 2 work each band, 3 each band/mode, 4 no dupe checking
55
+ dupe_type = 2
56
+
57
+
58
+ def init_contest(self):
59
+ """setup plugin"""
60
+ set_tab_next(self)
61
+ set_tab_prev(self)
62
+ interface(self)
63
+ self.next_field = self.other_1
64
+
65
+
66
+ def interface(self):
67
+ """Setup user interface"""
68
+ self.field1.hide()
69
+ self.field2.hide()
70
+ self.field3.show()
71
+ self.field4.show()
72
+ namefield = self.field3.findChild(QtWidgets.QLabel)
73
+ namefield.setText("Name")
74
+ self.field3.setAccessibleName("Name")
75
+ spc = self.field4.findChild(QtWidgets.QLabel)
76
+ spc.setText("SPC")
77
+ self.field4.setAccessibleName("SPC")
78
+
79
+
80
+ def reset_label(self):
81
+ """reset label after field cleared"""
82
+
83
+
84
+ def set_tab_next(self):
85
+ """Set TAB Advances"""
86
+ self.tab_next = {
87
+ self.callsign: self.field3.findChild(QtWidgets.QLineEdit),
88
+ self.field3.findChild(QtWidgets.QLineEdit): self.field4.findChild(
89
+ QtWidgets.QLineEdit
90
+ ),
91
+ self.field4.findChild(QtWidgets.QLineEdit): self.callsign,
92
+ }
93
+
94
+
95
+ def set_tab_prev(self):
96
+ """Set TAB Advances"""
97
+ self.tab_prev = {
98
+ self.callsign: self.field4.findChild(QtWidgets.QLineEdit),
99
+ self.field3.findChild(QtWidgets.QLineEdit): self.callsign,
100
+ self.field4.findChild(QtWidgets.QLineEdit): self.field3.findChild(
101
+ QtWidgets.QLineEdit
102
+ ),
103
+ }
104
+
105
+
106
+ def set_contact_vars(self):
107
+ """Contest Specific"""
108
+ self.contact["SNT"] = self.sent.text()
109
+ self.contact["RCV"] = self.receive.text()
110
+ self.contact["Name"] = self.other_1.text().upper()
111
+ self.contact["Sect"] = self.other_2.text().upper()
112
+ self.contact["SentNr"] = self.contest_settings.get("SentExchange", 0)
113
+ self.contact["Exchange1"] = (
114
+ f"{self.other_1.text().upper()} {self.other_2.text().upper()}"
115
+ )
116
+
117
+ result = self.database.fetch_call_exists(self.callsign.text())
118
+ # result = ALTEREGO.database.fetch_call_exists(self.callsign.text())
119
+ if result.get("call_count", ""):
120
+ self.contact["IsMultiplier1"] = 0
121
+ else:
122
+ self.contact["IsMultiplier1"] = 1
123
+
124
+
125
+ def predupe(self):
126
+ """called after callsign entered"""
127
+
128
+
129
+ def prefill(self):
130
+ """Fill sentnr"""
131
+
132
+
133
+ def points(self):
134
+ """Calc point"""
135
+ return 1
136
+
137
+
138
+ def show_mults(self):
139
+ """Return display string for mults"""
140
+ result = self.database.fetch_section_band_count_nodx()
141
+ if result:
142
+ return int(result.get("sb_count", 0))
143
+ return 0
144
+
145
+
146
+ def show_qso(self):
147
+ """Return qso count"""
148
+ result = self.database.fetch_qso_count()
149
+ if result:
150
+ return int(result.get("qsos", 0))
151
+ return 0
152
+
153
+
154
+ def calc_score(self):
155
+ """Return calculated score"""
156
+ result = self.database.fetch_points()
157
+ if result is not None:
158
+ score = result.get("Points", "0")
159
+ if score is None:
160
+ score = "0"
161
+ contest_points = int(score)
162
+ mults = show_mults(self)
163
+ return contest_points * mults
164
+ return 0
165
+
166
+
167
+ def adif(self):
168
+ """Call the generate ADIF function"""
169
+ gen_adif(self, cabrillo_name, cabrillo_name)
170
+
171
+
172
+ def cabrillo(self):
173
+ """Generates Cabrillo file. Maybe."""
174
+ # https://www.cqwpx.com/cabrillo.htm
175
+ logger.debug("******Cabrillo*****")
176
+ logger.debug("Station: %s", f"{self.station}")
177
+ logger.debug("Contest: %s", f"{self.contest_settings}")
178
+ now = datetime.datetime.now()
179
+ date_time = now.strftime("%Y-%m-%d_%H-%M-%S")
180
+ filename = (
181
+ str(Path.home())
182
+ + "/"
183
+ + f"{self.station.get('Call','').upper()}_{cabrillo_name}_{date_time}.log"
184
+ )
185
+ logger.debug("%s", filename)
186
+ log = self.database.fetch_all_contacts_asc()
187
+ try:
188
+ with open(filename, "w", encoding="ascii") as file_descriptor:
189
+ print("START-OF-LOG: 3.0", end="\r\n", file=file_descriptor)
190
+ print(
191
+ f"CREATED-BY: Not1MM v{__version__}",
192
+ end="\r\n",
193
+ file=file_descriptor,
194
+ )
195
+ print(
196
+ f"CONTEST: {cabrillo_name}",
197
+ end="\r\n",
198
+ file=file_descriptor,
199
+ )
200
+ if self.station.get("Club", ""):
201
+ print(
202
+ f"CLUB: {self.station.get('Club', '').upper()}",
203
+ end="\r\n",
204
+ file=file_descriptor,
205
+ )
206
+ print(
207
+ f"CALLSIGN: {self.station.get('Call','')}",
208
+ end="\r\n",
209
+ file=file_descriptor,
210
+ )
211
+ print(
212
+ f"LOCATION: {self.station.get('ARRLSection', '')}",
213
+ end="\r\n",
214
+ file=file_descriptor,
215
+ )
216
+ # print(
217
+ # f"ARRL-SECTION: {self.pref.get('section', '')}",
218
+ # end="\r\n",
219
+ # file=file_descriptor,
220
+ # )
221
+ print(
222
+ f"CATEGORY-OPERATOR: {self.contest_settings.get('OperatorCategory','')}",
223
+ end="\r\n",
224
+ file=file_descriptor,
225
+ )
226
+ print(
227
+ f"CATEGORY-ASSISTED: {self.contest_settings.get('AssistedCategory','')}",
228
+ end="\r\n",
229
+ file=file_descriptor,
230
+ )
231
+ print(
232
+ f"CATEGORY-BAND: {self.contest_settings.get('BandCategory','')}",
233
+ end="\r\n",
234
+ file=file_descriptor,
235
+ )
236
+ print(
237
+ f"CATEGORY-MODE: {self.contest_settings.get('ModeCategory','')}",
238
+ end="\r\n",
239
+ file=file_descriptor,
240
+ )
241
+ print(
242
+ f"CATEGORY-TRANSMITTER: {self.contest_settings.get('TransmitterCategory','')}",
243
+ end="\r\n",
244
+ file=file_descriptor,
245
+ )
246
+ if self.contest_settings.get("OverlayCategory", "") != "N/A":
247
+ print(
248
+ f"CATEGORY-OVERLAY: {self.contest_settings.get('OverlayCategory','')}",
249
+ end="\r\n",
250
+ file=file_descriptor,
251
+ )
252
+ print(
253
+ f"GRID-LOCATOR: {self.station.get('GridSquare','')}",
254
+ end="\r\n",
255
+ file=file_descriptor,
256
+ )
257
+ # print(
258
+ # f"CATEGORY: {None}",
259
+ # end="\r\n",
260
+ # file=file_descriptor,
261
+ # )
262
+ print(
263
+ f"CATEGORY-POWER: {self.contest_settings.get('PowerCategory','')}",
264
+ end="\r\n",
265
+ file=file_descriptor,
266
+ )
267
+
268
+ print(
269
+ f"CLAIMED-SCORE: {calc_score(self)}",
270
+ end="\r\n",
271
+ file=file_descriptor,
272
+ )
273
+ ops = f"@{self.station.get('Call','')}"
274
+ list_of_ops = self.database.get_ops()
275
+ for op in list_of_ops:
276
+ ops += f", {op.get('Operator', '')}"
277
+ print(
278
+ f"OPERATORS: {ops}",
279
+ end="\r\n",
280
+ file=file_descriptor,
281
+ )
282
+ print(
283
+ f"NAME: {self.station.get('Name', '')}",
284
+ end="\r\n",
285
+ file=file_descriptor,
286
+ )
287
+ print(
288
+ f"ADDRESS: {self.station.get('Street1', '')}",
289
+ end="\r\n",
290
+ file=file_descriptor,
291
+ )
292
+ print(
293
+ f"ADDRESS-CITY: {self.station.get('City', '')}",
294
+ end="\r\n",
295
+ file=file_descriptor,
296
+ )
297
+ print(
298
+ f"ADDRESS-STATE-PROVINCE: {self.station.get('State', '')}",
299
+ end="\r\n",
300
+ file=file_descriptor,
301
+ )
302
+ print(
303
+ f"ADDRESS-POSTALCODE: {self.station.get('Zip', '')}",
304
+ end="\r\n",
305
+ file=file_descriptor,
306
+ )
307
+ print(
308
+ f"ADDRESS-COUNTRY: {self.station.get('Country', '')}",
309
+ end="\r\n",
310
+ file=file_descriptor,
311
+ )
312
+ print(
313
+ f"EMAIL: {self.station.get('Email', '')}",
314
+ end="\r\n",
315
+ file=file_descriptor,
316
+ )
317
+ for contact in log:
318
+ the_date_and_time = contact.get("TS", "")
319
+ themode = contact.get("Mode", "")
320
+ if themode == "RTTY":
321
+ themode = "RY"
322
+ frequency = str(int(contact.get("Freq", "0"))).rjust(5)
323
+
324
+ loggeddate = the_date_and_time[:10]
325
+ loggedtime = the_date_and_time[11:13] + the_date_and_time[14:16]
326
+ exch1 = ""
327
+ exch2 = ""
328
+ if " " in str(contact.get("Exchange1", "")):
329
+ exch1, exch2 = str(contact.get("Exchange1", "")).strip().split(" ")
330
+ print(
331
+ f"QSO: {frequency} {themode} {loggeddate} {loggedtime} "
332
+ f"{contact.get('StationPrefix', '').ljust(13)} "
333
+ f"{str(contact.get('SentNr', '')).upper()} "
334
+ f"{contact.get('Call', '').ljust(13)} "
335
+ f"{exch1.ljust(10)} "
336
+ f"{exch2.ljust(5)} ",
337
+ end="\r\n",
338
+ file=file_descriptor,
339
+ )
340
+ print("END-OF-LOG:", end="\r\n", file=file_descriptor)
341
+ self.show_message_box(f"Cabrillo saved to: {filename}")
342
+ except IOError as exception:
343
+ logger.critical("cabrillo: IO error: %s, writing to %s", exception, filename)
344
+ self.show_message_box(f"Error saving Cabrillo: {exception} {filename}")
345
+ return
346
+
347
+
348
+ def recalculate_mults(self):
349
+ """Recalculates multipliers after change in logged qso."""
350
+
351
+ all_contacts = self.database.fetch_all_contacts_asc()
352
+ for contact in all_contacts:
353
+ time_stamp = contact.get("TS", "")
354
+ call = contact.get("Call", "")
355
+ query = (
356
+ f"select count(*) as call_count from dxlog where TS < '{time_stamp}' "
357
+ f"and Call = '{call}' "
358
+ f"and ContestNR = {self.pref.get('contest', '1')};"
359
+ )
360
+ result = self.database.exec_sql(query)
361
+ count = result.get("call_count", 1)
362
+ if count == 0:
363
+ contact["IsMultiplier1"] = 1
364
+ else:
365
+ contact["IsMultiplier1"] = 0
366
+ self.database.change_contact(contact)
367
+ cmd = {}
368
+ cmd["cmd"] = "UPDATELOG"
369
+ cmd["station"] = platform.node()
370
+ self.multicast_interface.send_as_json(cmd)
371
+
372
+
373
+ def set_self(the_outie):
374
+ """..."""
375
+ globals()["ALTEREGO"] = the_outie
376
+
377
+
378
+ def ft8_handler(the_packet: dict):
379
+ """Process FT8 QSO packets
380
+
381
+ FlDigi
382
+ {
383
+ 'FREQ': '7.029500',
384
+ 'CALL': 'DL2DSL',
385
+ 'MODE': 'RTTY',
386
+ 'NAME': 'BOB',result = ALTEREGO.database.fetch_call_exists(the_packet.get("CALL", ""))
387
+ if result.get("call_count", ""):
388
+ ALTEREGO.contact["IsMultiplier1"] = 0
389
+ else:
390
+ ALTEREGO.contact["IsMultiplier1"] = 1
391
+ 'QSO_DATE': '20240904',
392
+ 'QSO_DATE_OFF': '20240904',
393
+ 'TIME_OFF': '212825',
394
+ 'TIME_ON': '212800',
395
+ 'RST_RCVD': '599',
396
+ 'RST_SENT': '599',
397
+ 'BAND': '40M',
398
+ 'COUNTRY': 'FED. REP. OF GERMANY',
399
+ 'CQZ': '14',
400
+ 'STX': '000',
401
+ 'STX_STRING': '1D ORG',
402
+ 'CLASS': '1D',
403
+ 'ARRL_SECT': 'DX',
404
+ 'TX_PWR': '0',
405
+ 'OPERATOR': 'K6GTE',
406
+ 'STATION_CALLSIGN': 'K6GTE',
407
+ 'MY_GRIDSQUARE': 'DM13AT',
408
+ 'MY_CITY': 'ANAHEIM, CA',
409
+ 'MY_STATE': 'CA'
410
+ }
411
+
412
+ """
413
+ logger.debug(f"{the_packet=}")
414
+ if ALTEREGO is not None:
415
+ ALTEREGO.callsign.setText(the_packet.get("CALL"))
416
+ ALTEREGO.contact["Call"] = the_packet.get("CALL", "")
417
+ ALTEREGO.contact["SNT"] = ALTEREGO.sent.text()
418
+ ALTEREGO.contact["RCV"] = ALTEREGO.receive.text()
419
+ ALTEREGO.contact["Exchange1"] = the_packet.get("SRX_STRING", "")
420
+ exch1 = ""
421
+ exch2 = ""
422
+ if " " in str(the_packet.get("SRX_STRING", "")):
423
+ exch1, exch2 = str(the_packet.get("SRX_STRING", "")).strip().split(" ")
424
+ ALTEREGO.other_1.setText(exch1)
425
+ ALTEREGO.other_2.setText(exch2)
426
+ # ALTEREGO.contact["Sect"] = the_packet.get("ARRL_SECT", "ERR")
427
+ ALTEREGO.contact["Mode"] = the_packet.get("MODE", "ERR")
428
+ ALTEREGO.contact["Freq"] = round(float(the_packet.get("FREQ", "0.0")) * 1000, 2)
429
+ ALTEREGO.contact["QSXFreq"] = round(
430
+ float(the_packet.get("FREQ", "0.0")) * 1000, 2
431
+ )
432
+ ALTEREGO.contact["Band"] = get_logged_band(
433
+ str(int(float(the_packet.get("FREQ", "0.0")) * 1000000))
434
+ )
435
+
436
+ result = ALTEREGO.database.fetch_call_exists(the_packet.get("CALL", ""))
437
+ if result.get("call_count", ""):
438
+ ALTEREGO.contact["IsMultiplier1"] = 0
439
+ else:
440
+ ALTEREGO.contact["IsMultiplier1"] = 1
441
+ logger.debug(f"{ALTEREGO.contact=}")
442
+ ALTEREGO.save_contact()