not1mm 24.6.1__py3-none-any.whl → 24.7.12__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/data/MASTER.SCP +1556 -1049
- not1mm/data/configuration.ui +34 -34
- not1mm/data/cty.json +1 -1
- not1mm/data/main.ui +94 -94
- not1mm/data/settings.ui +5 -5
- not1mm/lib/n1mm.py +23 -0
- not1mm/lib/version.py +1 -1
- not1mm/plugins/k1usn_sst.py +343 -0
- not1mm/plugins/phone_weekly_test.py +1 -1
- {not1mm-24.6.1.dist-info → not1mm-24.7.12.dist-info}/METADATA +73 -26
- {not1mm-24.6.1.dist-info → not1mm-24.7.12.dist-info}/RECORD +15 -15
- {not1mm-24.6.1.dist-info → not1mm-24.7.12.dist-info}/WHEEL +1 -1
- {not1mm-24.6.1.dist-info → not1mm-24.7.12.dist-info}/LICENSE +0 -0
- {not1mm-24.6.1.dist-info → not1mm-24.7.12.dist-info}/entry_points.txt +0 -0
- {not1mm-24.6.1.dist-info → not1mm-24.7.12.dist-info}/top_level.txt +0 -0
not1mm/data/settings.ui
CHANGED
@@ -1255,7 +1255,7 @@
|
|
1255
1255
|
</palette>
|
1256
1256
|
</property>
|
1257
1257
|
<property name="focusPolicy">
|
1258
|
-
<enum>Qt::StrongFocus</enum>
|
1258
|
+
<enum>Qt::FocusPolicy::StrongFocus</enum>
|
1259
1259
|
</property>
|
1260
1260
|
<property name="accessibleName">
|
1261
1261
|
<string>c q zone</string>
|
@@ -1374,7 +1374,7 @@
|
|
1374
1374
|
<item>
|
1375
1375
|
<spacer name="horizontalSpacer_2">
|
1376
1376
|
<property name="orientation">
|
1377
|
-
<enum>Qt::Horizontal</enum>
|
1377
|
+
<enum>Qt::Orientation::Horizontal</enum>
|
1378
1378
|
</property>
|
1379
1379
|
<property name="sizeHint" stdset="0">
|
1380
1380
|
<size>
|
@@ -1387,10 +1387,10 @@
|
|
1387
1387
|
<item>
|
1388
1388
|
<widget class="QDialogButtonBox" name="buttonBox">
|
1389
1389
|
<property name="orientation">
|
1390
|
-
<enum>Qt::Horizontal</enum>
|
1390
|
+
<enum>Qt::Orientation::Horizontal</enum>
|
1391
1391
|
</property>
|
1392
1392
|
<property name="standardButtons">
|
1393
|
-
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
1393
|
+
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
|
1394
1394
|
</property>
|
1395
1395
|
<property name="centerButtons">
|
1396
1396
|
<bool>true</bool>
|
@@ -1400,7 +1400,7 @@
|
|
1400
1400
|
<item>
|
1401
1401
|
<spacer name="horizontalSpacer">
|
1402
1402
|
<property name="orientation">
|
1403
|
-
<enum>Qt::Horizontal</enum>
|
1403
|
+
<enum>Qt::Orientation::Horizontal</enum>
|
1404
1404
|
</property>
|
1405
1405
|
<property name="sizeHint" stdset="0">
|
1406
1406
|
<size>
|
not1mm/lib/n1mm.py
CHANGED
@@ -102,6 +102,21 @@ class N1MM:
|
|
102
102
|
"ID": "",
|
103
103
|
}
|
104
104
|
|
105
|
+
score_report = {
|
106
|
+
"app": "NOT1MM",
|
107
|
+
"contest": "",
|
108
|
+
"call": "",
|
109
|
+
"class": {
|
110
|
+
"ops": "SINGLE-OP",
|
111
|
+
"mode": "MIXED",
|
112
|
+
"power": "LOW",
|
113
|
+
"bands": "ALL",
|
114
|
+
"transmitter": "ONE",
|
115
|
+
},
|
116
|
+
"score": 0,
|
117
|
+
"timestamp": "",
|
118
|
+
}
|
119
|
+
|
105
120
|
def __init__(
|
106
121
|
self,
|
107
122
|
radioport="127.0.0.1:12060",
|
@@ -159,6 +174,14 @@ class N1MM:
|
|
159
174
|
"""Send lookup request"""
|
160
175
|
self._send(self.lookup_port, self.contact_info, "lookupinfo")
|
161
176
|
|
177
|
+
def send_score(self):
|
178
|
+
"""Send score"""
|
179
|
+
self._send(self.score_port, self.score_report, "scoreinfo")
|
180
|
+
|
181
|
+
def send_realtime_score(self):
|
182
|
+
"""Send score"""
|
183
|
+
self._send(self.score_port, self.score_report, "dynamicresults")
|
184
|
+
|
162
185
|
def _send(self, port_list, payload, package_name):
|
163
186
|
"""Send XML data"""
|
164
187
|
# bytes_to_send = dicttoxml(
|
not1mm/lib/version.py
CHANGED
not1mm/plugins/k1usn_sst.py
CHANGED
@@ -21,4 +21,347 @@
|
|
21
21
|
# Find rules at: http://www.k1usn.com/sst.html
|
22
22
|
|
23
23
|
import datetime
|
24
|
+
import logging
|
25
|
+
import platform
|
24
26
|
|
27
|
+
from pathlib import Path
|
28
|
+
|
29
|
+
from PyQt6 import QtWidgets
|
30
|
+
|
31
|
+
from not1mm.lib.plugin_common import gen_adif, get_points
|
32
|
+
from not1mm.lib.version import __version__
|
33
|
+
|
34
|
+
logger = logging.getLogger(__name__)
|
35
|
+
|
36
|
+
EXCHANGE_HINT = "Name or Name + SPC"
|
37
|
+
|
38
|
+
name = "PHONE WEEKLY TEST"
|
39
|
+
cabrillo_name = "PHONE-WEEKLY-TEST"
|
40
|
+
mode = "SSB" # CW SSB BOTH RTTY
|
41
|
+
# columns = [0, 1, 2, 3, 4, 10, 11, 14, 15]
|
42
|
+
columns = [
|
43
|
+
"YYYY-MM-DD HH:MM:SS",
|
44
|
+
"Call",
|
45
|
+
"Freq",
|
46
|
+
"Name",
|
47
|
+
"Sect",
|
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("State")
|
77
|
+
self.field4.setAccessibleName("State")
|
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
|
+
|
114
|
+
if self.contact.get("Sect", ""):
|
115
|
+
result = self.database.fetch_sect_band_exists(
|
116
|
+
self.contact.get("Sect", ""), self.contact.get("Band", "")
|
117
|
+
)
|
118
|
+
if result.get("sect_count", ""):
|
119
|
+
self.contact["IsMultiplier1"] = 0
|
120
|
+
else:
|
121
|
+
self.contact["IsMultiplier1"] = 1
|
122
|
+
|
123
|
+
|
124
|
+
def predupe(self):
|
125
|
+
"""called after callsign entered"""
|
126
|
+
|
127
|
+
|
128
|
+
def prefill(self):
|
129
|
+
"""Fill sentnr"""
|
130
|
+
|
131
|
+
|
132
|
+
def points(self):
|
133
|
+
"""Calc point"""
|
134
|
+
return 1
|
135
|
+
|
136
|
+
|
137
|
+
def show_mults(self):
|
138
|
+
"""Return display string for mults"""
|
139
|
+
result = self.database.fetch_section_band_count_nodx()
|
140
|
+
if result:
|
141
|
+
return int(result.get("sb_count", 0))
|
142
|
+
return 0
|
143
|
+
|
144
|
+
|
145
|
+
def show_qso(self):
|
146
|
+
"""Return qso count"""
|
147
|
+
result = self.database.fetch_qso_count()
|
148
|
+
if result:
|
149
|
+
return int(result.get("qsos", 0))
|
150
|
+
return 0
|
151
|
+
|
152
|
+
|
153
|
+
def calc_score(self):
|
154
|
+
"""Return calculated score"""
|
155
|
+
result = self.database.fetch_points()
|
156
|
+
if result is not None:
|
157
|
+
score = result.get("Points", "0")
|
158
|
+
if score is None:
|
159
|
+
score = "0"
|
160
|
+
contest_points = int(score)
|
161
|
+
mults = show_mults(self)
|
162
|
+
return contest_points * mults
|
163
|
+
return 0
|
164
|
+
|
165
|
+
|
166
|
+
def adif(self):
|
167
|
+
"""Call the generate ADIF function"""
|
168
|
+
gen_adif(self, cabrillo_name, "K1USN-SST")
|
169
|
+
|
170
|
+
|
171
|
+
def cabrillo(self):
|
172
|
+
"""Generates Cabrillo file. Maybe."""
|
173
|
+
# https://www.cqwpx.com/cabrillo.htm
|
174
|
+
logger.debug("******Cabrillo*****")
|
175
|
+
logger.debug("Station: %s", f"{self.station}")
|
176
|
+
logger.debug("Contest: %s", f"{self.contest_settings}")
|
177
|
+
now = datetime.datetime.now()
|
178
|
+
date_time = now.strftime("%Y-%m-%d_%H-%M-%S")
|
179
|
+
filename = (
|
180
|
+
str(Path.home())
|
181
|
+
+ "/"
|
182
|
+
+ f"{self.station.get('Call','').upper()}_{cabrillo_name}_{date_time}.log"
|
183
|
+
)
|
184
|
+
logger.debug("%s", filename)
|
185
|
+
log = self.database.fetch_all_contacts_asc()
|
186
|
+
try:
|
187
|
+
with open(filename, "w", encoding="ascii") as file_descriptor:
|
188
|
+
print("START-OF-LOG: 3.0", end="\r\n", file=file_descriptor)
|
189
|
+
print(
|
190
|
+
f"CREATED-BY: Not1MM v{__version__}",
|
191
|
+
end="\r\n",
|
192
|
+
file=file_descriptor,
|
193
|
+
)
|
194
|
+
print(
|
195
|
+
f"CONTEST: {cabrillo_name}",
|
196
|
+
end="\r\n",
|
197
|
+
file=file_descriptor,
|
198
|
+
)
|
199
|
+
if self.station.get("Club", ""):
|
200
|
+
print(
|
201
|
+
f"CLUB: {self.station.get('Club', '').upper()}",
|
202
|
+
end="\r\n",
|
203
|
+
file=file_descriptor,
|
204
|
+
)
|
205
|
+
print(
|
206
|
+
f"CALLSIGN: {self.station.get('Call','')}",
|
207
|
+
end="\r\n",
|
208
|
+
file=file_descriptor,
|
209
|
+
)
|
210
|
+
print(
|
211
|
+
f"LOCATION: {self.station.get('ARRLSection', '')}",
|
212
|
+
end="\r\n",
|
213
|
+
file=file_descriptor,
|
214
|
+
)
|
215
|
+
# print(
|
216
|
+
# f"ARRL-SECTION: {self.pref.get('section', '')}",
|
217
|
+
# end="\r\n",
|
218
|
+
# file=file_descriptor,
|
219
|
+
# )
|
220
|
+
print(
|
221
|
+
f"CATEGORY-OPERATOR: {self.contest_settings.get('OperatorCategory','')}",
|
222
|
+
end="\r\n",
|
223
|
+
file=file_descriptor,
|
224
|
+
)
|
225
|
+
print(
|
226
|
+
f"CATEGORY-ASSISTED: {self.contest_settings.get('AssistedCategory','')}",
|
227
|
+
end="\r\n",
|
228
|
+
file=file_descriptor,
|
229
|
+
)
|
230
|
+
print(
|
231
|
+
f"CATEGORY-BAND: {self.contest_settings.get('BandCategory','')}",
|
232
|
+
end="\r\n",
|
233
|
+
file=file_descriptor,
|
234
|
+
)
|
235
|
+
print(
|
236
|
+
f"CATEGORY-MODE: {self.contest_settings.get('ModeCategory','')}",
|
237
|
+
end="\r\n",
|
238
|
+
file=file_descriptor,
|
239
|
+
)
|
240
|
+
print(
|
241
|
+
f"CATEGORY-TRANSMITTER: {self.contest_settings.get('TransmitterCategory','')}",
|
242
|
+
end="\r\n",
|
243
|
+
file=file_descriptor,
|
244
|
+
)
|
245
|
+
if self.contest_settings.get("OverlayCategory", "") != "N/A":
|
246
|
+
print(
|
247
|
+
f"CATEGORY-OVERLAY: {self.contest_settings.get('OverlayCategory','')}",
|
248
|
+
end="\r\n",
|
249
|
+
file=file_descriptor,
|
250
|
+
)
|
251
|
+
print(
|
252
|
+
f"GRID-LOCATOR: {self.station.get('GridSquare','')}",
|
253
|
+
end="\r\n",
|
254
|
+
file=file_descriptor,
|
255
|
+
)
|
256
|
+
# print(
|
257
|
+
# f"CATEGORY: {None}",
|
258
|
+
# end="\r\n",
|
259
|
+
# file=file_descriptor,
|
260
|
+
# )
|
261
|
+
print(
|
262
|
+
f"CATEGORY-POWER: {self.contest_settings.get('PowerCategory','')}",
|
263
|
+
end="\r\n",
|
264
|
+
file=file_descriptor,
|
265
|
+
)
|
266
|
+
|
267
|
+
print(
|
268
|
+
f"CLAIMED-SCORE: {calc_score(self)}",
|
269
|
+
end="\r\n",
|
270
|
+
file=file_descriptor,
|
271
|
+
)
|
272
|
+
ops = f"@{self.station.get('Call','')}"
|
273
|
+
list_of_ops = self.database.get_ops()
|
274
|
+
for op in list_of_ops:
|
275
|
+
ops += f", {op.get('Operator', '')}"
|
276
|
+
print(
|
277
|
+
f"OPERATORS: {ops}",
|
278
|
+
end="\r\n",
|
279
|
+
file=file_descriptor,
|
280
|
+
)
|
281
|
+
print(
|
282
|
+
f"NAME: {self.station.get('Name', '')}",
|
283
|
+
end="\r\n",
|
284
|
+
file=file_descriptor,
|
285
|
+
)
|
286
|
+
print(
|
287
|
+
f"ADDRESS: {self.station.get('Street1', '')}",
|
288
|
+
end="\r\n",
|
289
|
+
file=file_descriptor,
|
290
|
+
)
|
291
|
+
print(
|
292
|
+
f"ADDRESS-CITY: {self.station.get('City', '')}",
|
293
|
+
end="\r\n",
|
294
|
+
file=file_descriptor,
|
295
|
+
)
|
296
|
+
print(
|
297
|
+
f"ADDRESS-STATE-PROVINCE: {self.station.get('State', '')}",
|
298
|
+
end="\r\n",
|
299
|
+
file=file_descriptor,
|
300
|
+
)
|
301
|
+
print(
|
302
|
+
f"ADDRESS-POSTALCODE: {self.station.get('Zip', '')}",
|
303
|
+
end="\r\n",
|
304
|
+
file=file_descriptor,
|
305
|
+
)
|
306
|
+
print(
|
307
|
+
f"ADDRESS-COUNTRY: {self.station.get('Country', '')}",
|
308
|
+
end="\r\n",
|
309
|
+
file=file_descriptor,
|
310
|
+
)
|
311
|
+
print(
|
312
|
+
f"EMAIL: {self.station.get('Email', '')}",
|
313
|
+
end="\r\n",
|
314
|
+
file=file_descriptor,
|
315
|
+
)
|
316
|
+
for contact in log:
|
317
|
+
the_date_and_time = contact.get("TS", "")
|
318
|
+
themode = contact.get("Mode", "")
|
319
|
+
if themode == "LSB" or themode == "USB":
|
320
|
+
themode = "PH"
|
321
|
+
frequency = str(int(contact.get("Freq", "0"))).rjust(5)
|
322
|
+
|
323
|
+
loggeddate = the_date_and_time[:10]
|
324
|
+
loggedtime = the_date_and_time[11:13] + the_date_and_time[14:16]
|
325
|
+
print(
|
326
|
+
f"QSO: {frequency} {themode} {loggeddate} {loggedtime} "
|
327
|
+
f"{contact.get('StationPrefix', '').ljust(13)} "
|
328
|
+
f"{str(contact.get('SentNr', '')).upper()} "
|
329
|
+
f"{contact.get('Call', '').ljust(13)} "
|
330
|
+
f"{str(contact.get('Name', '')).ljust(11)} "
|
331
|
+
f"{str(contact.get('Sect', '')).ljust(5)}",
|
332
|
+
end="\r\n",
|
333
|
+
file=file_descriptor,
|
334
|
+
)
|
335
|
+
print("END-OF-LOG:", end="\r\n", file=file_descriptor)
|
336
|
+
self.show_message_box(f"Cabrillo saved to: {filename}")
|
337
|
+
except IOError as exception:
|
338
|
+
logger.critical("cabrillo: IO error: %s, writing to %s", exception, filename)
|
339
|
+
self.show_message_box(f"Error saving Cabrillo: {exception} {filename}")
|
340
|
+
return
|
341
|
+
|
342
|
+
|
343
|
+
def recalculate_mults(self):
|
344
|
+
"""Recalculates multipliers after change in logged qso."""
|
345
|
+
|
346
|
+
all_contacts = self.database.fetch_all_contacts_asc()
|
347
|
+
for contact in all_contacts:
|
348
|
+
time_stamp = contact.get("TS", "")
|
349
|
+
sect = contact.get("Sect", "")
|
350
|
+
band = contact.get("Band", "")
|
351
|
+
query = (
|
352
|
+
f"select count(*) as sect_count from dxlog where TS < '{time_stamp}' "
|
353
|
+
f"and Sect = '{sect}' "
|
354
|
+
f"and Band = '{band}' "
|
355
|
+
f"and ContestNR = {self.pref.get('contest', '1')};"
|
356
|
+
)
|
357
|
+
result = self.database.exec_sql(query)
|
358
|
+
count = result.get("sect_count", 1)
|
359
|
+
if count == 0 and contact.get("Points", 0) == 1 and sect != "DX":
|
360
|
+
contact["IsMultiplier1"] = 1
|
361
|
+
else:
|
362
|
+
contact["IsMultiplier1"] = 0
|
363
|
+
self.database.change_contact(contact)
|
364
|
+
cmd = {}
|
365
|
+
cmd["cmd"] = "UPDATELOG"
|
366
|
+
cmd["station"] = platform.node()
|
367
|
+
self.multicast_interface.send_as_json(cmd)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: not1mm
|
3
|
-
Version: 24.
|
3
|
+
Version: 24.7.12
|
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
|
@@ -44,9 +44,19 @@ Requires-Dist: Levenshtein
|
|
44
44
|
[](https://xkcd.com/1695/)
|
45
45
|
[](https://pypi.org/project/not1mm/)
|
46
46
|
|
47
|
+

|
48
|
+
|
47
49
|
- [Not1MM](#not1mm)
|
48
50
|
- [What and why is Not1MM](#what-and-why-is-not1mm)
|
51
|
+
- [The elephant in the room](#the-elephant-in-the-room)
|
52
|
+
- [The What](#the-what)
|
53
|
+
- [Target Environment](#target-environment)
|
54
|
+
- [The Why](#the-why)
|
55
|
+
- [General logging](#general-logging)
|
49
56
|
- [Current state](#current-state)
|
57
|
+
- [Code maturity](#code-maturity)
|
58
|
+
- [Data and RTTY](#data-and-rtty)
|
59
|
+
- [Other not so supported contests](#other-not-so-supported-contests)
|
50
60
|
- [Our Code Contributors ✨](#our-code-contributors-)
|
51
61
|
- [List of should be working contests](#list-of-should-be-working-contests)
|
52
62
|
- [Recent Changes](#recent-changes)
|
@@ -67,17 +77,18 @@ Requires-Dist: Levenshtein
|
|
67
77
|
- [After the install](#after-the-install)
|
68
78
|
- [You may or may not get a warning message like](#you-may-or-may-not-get-a-warning-message-like)
|
69
79
|
- [Or this fan favorite](#or-this-fan-favorite)
|
80
|
+
- [Update your CTY and SCP files](#update-your-cty-and-scp-files)
|
70
81
|
- [Various data file locations](#various-data-file-locations)
|
71
82
|
- [Data](#data)
|
72
83
|
- [Config](#config)
|
73
|
-
- [The
|
84
|
+
- [The Database](#the-database)
|
74
85
|
- [Why](#why)
|
75
|
-
- [The first one](#the-first-one)
|
86
|
+
- [The first one is free](#the-first-one-is-free)
|
76
87
|
- [Why limit yourself](#why-limit-yourself)
|
77
88
|
- [Revisiting an old friend](#revisiting-an-old-friend)
|
78
|
-
- [Station Settings dialog (REQUIRED)](#station-settings-dialog-required)
|
89
|
+
- [Station Settings dialog (It's REQUIRED Russ)](#station-settings-dialog-its-required-russ)
|
79
90
|
- [Changing station information](#changing-station-information)
|
80
|
-
- [Selecting a contest (REQUIRED)](#selecting-a-contest-required)
|
91
|
+
- [Selecting a contest (It's REQUIRED Russ)](#selecting-a-contest-its-required-russ)
|
81
92
|
- [Selecting a new contest](#selecting-a-new-contest)
|
82
93
|
- [Selecting an existing contest as the current contest](#selecting-an-existing-contest-as-the-current-contest)
|
83
94
|
- [Editing existing contest parameters](#editing-existing-contest-parameters)
|
@@ -113,34 +124,64 @@ Requires-Dist: Levenshtein
|
|
113
124
|
|
114
125
|
## What and why is Not1MM
|
115
126
|
|
127
|
+
### The elephant in the room
|
128
|
+
|
116
129
|
Not1MM's interface is a blatant ripoff of N1MM. It is NOT N1MM and any problem
|
117
130
|
you have with this software should in no way reflect on their software.
|
118
131
|
|
119
|
-
|
120
|
-
|
132
|
+
### The What
|
133
|
+
|
134
|
+
Not1MM attempts to be a useable amateur radio, or HAM, contest logger. It's
|
135
|
+
written in Python, 3.9+, and uses Qt6 framework for the graphical interface
|
136
|
+
and SQLite for the database.
|
137
|
+
|
138
|
+
### Target Environment
|
121
139
|
|
122
|
-
|
123
|
-
|
140
|
+
The primary target for this application is Linux. It may be able to run on other
|
141
|
+
platforms, BSD, Mac and Windows. But I don't have a way, or desire, to directly
|
142
|
+
support them.
|
124
143
|
|
125
|
-
|
126
|
-
|
127
|
-
|
144
|
+
### The Why
|
145
|
+
|
146
|
+
**Currently this exists for my own personal amusement**. I've recently retired
|
147
|
+
after 35+ years working for 'The Phone Company', GTE -> Verizon -> Frontier.
|
148
|
+
And being a Gentleman of Leisure, needed something to do in my free time.
|
149
|
+
I'm a casual contester and could not find any contesting software for Linux that
|
150
|
+
I wanted to use. There is [Tucnak](http://tucnak.nagano.cz/) which is very robust
|
151
|
+
and mature. It just wasn't for me.
|
152
|
+
|
153
|
+
### General logging
|
154
|
+
|
155
|
+
In short... Don't. There are much better general purpose QSO logging programs.
|
156
|
+
Try QLog or CQRLog.
|
128
157
|
|
129
158
|
## Current state
|
130
159
|
|
131
|
-
|
132
|
-
to work contacts and submit a cabrillo at the end. I'm not a "Contester". So
|
133
|
-
I'll add contests as/if I work them. I'm only one guy, so if you see a bug let
|
134
|
-
me know. I don't do much of any Data or RTTY operating. This is why you don't
|
135
|
-
see RTTY in the list of working contests. The Lord helps those who burn people
|
136
|
-
at the... I mean who help themselves. Feel free to fill in that hole with a pull
|
137
|
-
request.
|
160
|
+
### Code maturity
|
138
161
|
|
139
|
-
|
162
|
+
The current state is "**BETA**".
|
163
|
+
|
164
|
+
I've used it for quite a few contests, and was able to work contacts and submit
|
165
|
+
cabrillos at the end. There are still quite a few features I'd like to implement.
|
166
|
+
And "BETA" is a sort of get out of jail free badge for coders. A safety net for
|
167
|
+
when the program craps the bed. I'm only one guy, so if you see a bug let me know.
|
168
|
+
|
169
|
+
### Data and RTTY
|
170
|
+
|
171
|
+
I don't do much of any digital or RTTY operating. This is why you don't see RTTY in
|
172
|
+
the list of working contests. The Lord helps those who burn people at the... I
|
173
|
+
mean, who help themselves. Feel free to fill in that hole with a pull request.
|
174
|
+
|
175
|
+
### Other not so supported contests
|
176
|
+
|
177
|
+
Of note, state QSO parties. I haven't worked any yet. And no one has submitted a PR
|
178
|
+
adding one... So there you go. In the near future I'll probably add California, guess
|
179
|
+
where I live, and the 4 states QSO party.
|
140
180
|
|
141
181
|
## Our Code Contributors ✨
|
142
182
|
|
143
|
-
I wish to thank those who've contributed to the project.
|
183
|
+
I wish to thank those who've contributed to the project. Below is an automatically
|
184
|
+
generated, 'cause I'm lazy, list of those who've submitted PR's.
|
144
185
|
|
145
186
|
<a href="https://github.com/mbridak/not1mm/graphs/contributors">
|
146
187
|
<img src="https://contrib.rocks/image?repo=mbridak/not1mm" alt="Avatar icons for code contributors." />
|
@@ -182,6 +223,7 @@ I wish to thank those who've contributed to the project.
|
|
182
223
|
|
183
224
|
## Recent Changes
|
184
225
|
|
226
|
+
- [24-6-27] Corrected ADIF contest_id for the Phone Weekly Test.
|
185
227
|
- [24-6-1] Added leading zeros to S/N's less than 100.
|
186
228
|
|
187
229
|
See [CHANGELOG.md](CHANGELOG.md) for prior changes.
|
@@ -243,7 +285,7 @@ source .profile
|
|
243
285
|
|
244
286
|
</details>
|
245
287
|
|
246
|
-
<details>
|
288
|
+
<details>REQUIRED
|
247
289
|
|
248
290
|
<summary><b>Fedora 38, 39 and 40</b></summary>
|
249
291
|
|
@@ -394,6 +436,11 @@ For a more permanent solution you can place the line
|
|
394
436
|
`export QT_QPA_PLATFORM=wayland` in your home directories .bashrc file. Then
|
395
437
|
after logging out and back in you should be able to launch it normally.
|
396
438
|
|
439
|
+
### Update your CTY and SCP files
|
440
|
+
|
441
|
+
After all the configuration stuff below and before operating in a contest, you
|
442
|
+
might want to update the CTY and SCP files. You can do this by choosing FILE->Update CTY and FILE->Update MASTER.SCP
|
443
|
+
|
397
444
|
## Various data file locations
|
398
445
|
|
399
446
|
### Data
|
@@ -407,7 +454,7 @@ CW macro files can be found there. Otherwise they will be found at
|
|
407
454
|
Configuration file(s) can be found at the location defined by `XDG_CONFIG_HOME`.
|
408
455
|
Otherwise they will be found at `yourhome/.config/not1mm`
|
409
456
|
|
410
|
-
## The
|
457
|
+
## The Database
|
411
458
|
|
412
459
|
### Why
|
413
460
|
|
@@ -417,7 +464,7 @@ everything shown in the Station Settings dialog. You can have one database for
|
|
417
464
|
the rest of your life. Filled with hundreds of contests you've logged. Or, you
|
418
465
|
can create a new database to hold just one contest. You do You Boo.
|
419
466
|
|
420
|
-
### The first one
|
467
|
+
### The first one is free
|
421
468
|
|
422
469
|
On the initial running, a database is created for you called `ham.db`. This, and
|
423
470
|
all future databases, are located in the data directory mentioned above.
|
@@ -433,7 +480,7 @@ day for all I care. You can manage your own digital disaster.
|
|
433
480
|
You can select a previously created databases for use by selecting
|
434
481
|
`File` > `Open Database`.
|
435
482
|
|
436
|
-
## Station Settings dialog (REQUIRED)
|
483
|
+
## Station Settings dialog (It's REQUIRED Russ)
|
437
484
|
|
438
485
|
After initial run of the program or creating a new database you will need to
|
439
486
|
fill out the Station Settings dialog that will pop up.
|
@@ -453,7 +500,7 @@ You can fill. You can fill. Everyone look at your keys.
|
|
453
500
|
Station information can be changed any time by going to
|
454
501
|
`File` > `Station Settings` and editing the information.
|
455
502
|
|
456
|
-
## Selecting a contest (REQUIRED)
|
503
|
+
## Selecting a contest (It's REQUIRED Russ)
|
457
504
|
|
458
505
|
### Selecting a new contest
|
459
506
|
|