not1mm 23.12.5__py3-none-any.whl → 24.1.15__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 +249 -399
- not1mm/data/MASTER.SCP +1056 -48577
- not1mm/data/configuration.ui +93 -2
- not1mm/data/cty.json +1 -1
- not1mm/data/main.ui +186 -3
- not1mm/data/new_contest.ui +26 -1
- not1mm/lib/ham_utility.py +16 -4
- not1mm/lib/settings.py +40 -0
- not1mm/lib/version.py +1 -1
- not1mm/plugins/10_10_fall_cw.py +1 -1
- not1mm/plugins/10_10_spring_cw.py +1 -1
- not1mm/plugins/10_10_summer_phone.py +1 -1
- not1mm/plugins/10_10_winter_phone.py +1 -1
- not1mm/plugins/arrl_10m.py +413 -0
- not1mm/plugins/arrl_dx_cw.py +1 -1
- not1mm/plugins/arrl_dx_ssb.py +1 -1
- not1mm/plugins/arrl_ss_cw.py +4 -1
- not1mm/plugins/arrl_ss_phone.py +4 -1
- not1mm/plugins/arrl_vhf_jan.py +390 -0
- not1mm/plugins/arrl_vhf_jun.py +358 -0
- not1mm/plugins/arrl_vhf_sep.py +357 -0
- not1mm/plugins/canada_day.py +5 -2
- not1mm/plugins/cq_wpx_cw.py +1 -1
- not1mm/plugins/cq_wpx_ssb.py +1 -1
- not1mm/plugins/cq_ww_cw.py +1 -1
- not1mm/plugins/cq_ww_ssb.py +1 -1
- not1mm/plugins/cwt.py +5 -2
- not1mm/plugins/general_logging.py +1 -1
- not1mm/plugins/iaru_hf.py +1 -1
- not1mm/plugins/jidx_cw.py +2 -1
- not1mm/plugins/jidx_ph.py +2 -1
- not1mm/plugins/naqp_cw.py +1 -2
- not1mm/plugins/naqp_ssb.py +1 -2
- not1mm/plugins/phone_weekly_test.py +372 -0
- not1mm/plugins/stew_perry_topband.py +336 -0
- not1mm/weee.py +10 -0
- {not1mm-23.12.5.dist-info → not1mm-24.1.15.dist-info}/METADATA +19 -7
- {not1mm-23.12.5.dist-info → not1mm-24.1.15.dist-info}/RECORD +42 -35
- {not1mm-23.12.5.dist-info → not1mm-24.1.15.dist-info}/LICENSE +0 -0
- {not1mm-23.12.5.dist-info → not1mm-24.1.15.dist-info}/WHEEL +0 -0
- {not1mm-23.12.5.dist-info → not1mm-24.1.15.dist-info}/entry_points.txt +0 -0
- {not1mm-23.12.5.dist-info → not1mm-24.1.15.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,413 @@
|
|
1
|
+
"""
|
2
|
+
ARRL 10-Meter Contest
|
3
|
+
Status: Active
|
4
|
+
Geographic Focus: Worldwide
|
5
|
+
Participation: Worldwide
|
6
|
+
Mode: CW, Phone
|
7
|
+
Bands: 10m Only
|
8
|
+
Classes: Single Op (QRP/Low/High)(CW/Phone/Mixed)
|
9
|
+
Single Op Unlimited (QRP/Low/High)(CW/Phone/Mixed)
|
10
|
+
Single Op Overlay: (Limited Antennas)
|
11
|
+
Multi-Single (Low/High)
|
12
|
+
Max operating hours: 36 hours
|
13
|
+
Max power: HP: 1500 watts
|
14
|
+
LP: 100 watts
|
15
|
+
QRP: 5 watts
|
16
|
+
Exchange: W/VE: RST + State/Province
|
17
|
+
XE: RST + State
|
18
|
+
DX: RST + Serial No.
|
19
|
+
MM: RST + ITU Region
|
20
|
+
QSO Points: 2 points per Phone QSO
|
21
|
+
4 points per CW QSO
|
22
|
+
Multipliers: Each US State + DC once per mode
|
23
|
+
Each VE Province/Territory once per mode
|
24
|
+
Each XE State once per mode
|
25
|
+
Each DXCC Country once per mode
|
26
|
+
Each ITU Region (MM only) once per mode
|
27
|
+
Score Calculation: Total score = total QSO points x total mults
|
28
|
+
Find rules at: <http://www.arrl.org/10-meter>
|
29
|
+
Cabrillo name: ARRL-10
|
30
|
+
|
31
|
+
|
32
|
+
Scoring: Each phone contact counts for two (2) QSO points. Each CW contact counts for four (4) QSO
|
33
|
+
points. To calculate your final score, multiply the total QSO points by the number of US states (plus the
|
34
|
+
District of Columbia), Canadian Provinces and Territories, Mexican states, DXCC entities, and ITU
|
35
|
+
regions you contacted. Each multiplier counts once on phone and once on CW
|
36
|
+
|
37
|
+
Scoring Example: KA1RWY makes 2235 contacts including 1305 phone QSOs, and 930 CW QSOs, for
|
38
|
+
a total of 6330 QSO points. On phone, she works 49 states, 10 Canadian provinces, 3 Mexican states, 20
|
39
|
+
DXCC entities and a maritime mobile station in Region 2 for a total of 49+10+3+20+1 = 83 phone
|
40
|
+
multipliers. On CW she works 30 states, 8 Canadian provinces, 1 Mexican state, and 18 DXCC entities
|
41
|
+
for a total of 30+8+1+18 = 57 CW multipliers. Her final score = 6330 QSO points x (83+57) multipliers =
|
42
|
+
6330 x 140 = 886,200 points.
|
43
|
+
|
44
|
+
|
45
|
+
"""
|
46
|
+
|
47
|
+
# pylint: disable=invalid-name, unused-argument, unused-variable, c-extension-no-member
|
48
|
+
|
49
|
+
import datetime
|
50
|
+
import logging
|
51
|
+
|
52
|
+
from pathlib import Path
|
53
|
+
from PyQt5 import QtWidgets
|
54
|
+
|
55
|
+
from not1mm.lib.plugin_common import gen_adif, get_points
|
56
|
+
from not1mm.lib.version import __version__
|
57
|
+
|
58
|
+
logger = logging.getLogger("__main__")
|
59
|
+
|
60
|
+
name = "ARRL 10M"
|
61
|
+
mode = "BOTH" # CW SSB BOTH RTTY
|
62
|
+
cabrillo_name = "ARRL-10"
|
63
|
+
|
64
|
+
columns = [
|
65
|
+
"YYYY-MM-DD HH:MM:SS",
|
66
|
+
"Call",
|
67
|
+
"Freq",
|
68
|
+
"Snt",
|
69
|
+
"Rcv",
|
70
|
+
"SentNr",
|
71
|
+
"RcvNr",
|
72
|
+
"PTS",
|
73
|
+
]
|
74
|
+
|
75
|
+
advance_on_space = [True, True, True, True, True]
|
76
|
+
|
77
|
+
# 1 once per contest, 2 work each band, 3 each band/mode, 4 no dupe checking
|
78
|
+
dupe_type = 3
|
79
|
+
|
80
|
+
|
81
|
+
def init_contest(self):
|
82
|
+
"""setup plugin"""
|
83
|
+
set_tab_next(self)
|
84
|
+
set_tab_prev(self)
|
85
|
+
interface(self)
|
86
|
+
self.next_field = self.other_2
|
87
|
+
|
88
|
+
|
89
|
+
def interface(self):
|
90
|
+
"""Setup user interface"""
|
91
|
+
self.field1.show()
|
92
|
+
self.field2.show()
|
93
|
+
self.field3.show()
|
94
|
+
self.field4.show()
|
95
|
+
label = self.field3.findChild(QtWidgets.QLabel)
|
96
|
+
label.setText("SentNR")
|
97
|
+
self.field3.setAccessibleName("Sent Number")
|
98
|
+
label = self.field4.findChild(QtWidgets.QLabel)
|
99
|
+
label.setText("State|Prov|SN|ITU")
|
100
|
+
self.field4.setAccessibleName("State Province Serial Number or I T U Section")
|
101
|
+
|
102
|
+
|
103
|
+
def reset_label(self):
|
104
|
+
"""reset label after field cleared"""
|
105
|
+
|
106
|
+
|
107
|
+
def set_tab_next(self):
|
108
|
+
"""Set TAB Advances"""
|
109
|
+
self.tab_next = {
|
110
|
+
self.callsign: self.field1.findChild(QtWidgets.QLineEdit),
|
111
|
+
self.field1.findChild(QtWidgets.QLineEdit): self.field2.findChild(
|
112
|
+
QtWidgets.QLineEdit
|
113
|
+
),
|
114
|
+
self.field2.findChild(QtWidgets.QLineEdit): self.field3.findChild(
|
115
|
+
QtWidgets.QLineEdit
|
116
|
+
),
|
117
|
+
self.field3.findChild(QtWidgets.QLineEdit): self.field4.findChild(
|
118
|
+
QtWidgets.QLineEdit
|
119
|
+
),
|
120
|
+
self.field4.findChild(QtWidgets.QLineEdit): self.callsign,
|
121
|
+
}
|
122
|
+
|
123
|
+
|
124
|
+
def set_tab_prev(self):
|
125
|
+
"""Set TAB Advances"""
|
126
|
+
self.tab_prev = {
|
127
|
+
self.callsign: self.field4.findChild(QtWidgets.QLineEdit),
|
128
|
+
self.field1.findChild(QtWidgets.QLineEdit): self.callsign,
|
129
|
+
self.field2.findChild(QtWidgets.QLineEdit): self.field1.findChild(
|
130
|
+
QtWidgets.QLineEdit
|
131
|
+
),
|
132
|
+
self.field3.findChild(QtWidgets.QLineEdit): self.field2.findChild(
|
133
|
+
QtWidgets.QLineEdit
|
134
|
+
),
|
135
|
+
self.field4.findChild(QtWidgets.QLineEdit): self.field3.findChild(
|
136
|
+
QtWidgets.QLineEdit
|
137
|
+
),
|
138
|
+
}
|
139
|
+
|
140
|
+
|
141
|
+
def validate(self):
|
142
|
+
"""doc"""
|
143
|
+
# exchange = self.other_2.text().upper().split()
|
144
|
+
# if len(exchange) == 3:
|
145
|
+
# if exchange[0].isalpha() and exchange[1].isdigit() and exchange[2].isalpha():
|
146
|
+
# return True
|
147
|
+
# return False
|
148
|
+
return True
|
149
|
+
|
150
|
+
|
151
|
+
def set_contact_vars(self):
|
152
|
+
"""Contest Specific"""
|
153
|
+
self.contact["SNT"] = self.sent.text()
|
154
|
+
self.contact["RCV"] = self.receive.text()
|
155
|
+
self.contact["NR"] = self.other_2.text().upper()
|
156
|
+
self.contact["SentNr"] = self.other_1.text()
|
157
|
+
|
158
|
+
|
159
|
+
def predupe(self):
|
160
|
+
"""called after callsign entered"""
|
161
|
+
|
162
|
+
|
163
|
+
def prefill(self):
|
164
|
+
"""Fill sentnr"""
|
165
|
+
result = self.database.get_serial()
|
166
|
+
serial_nr = str(result.get("serial_nr", "1"))
|
167
|
+
if serial_nr == "None":
|
168
|
+
serial_nr = "1"
|
169
|
+
|
170
|
+
exchange = self.contest_settings.get("SentExchange", "").replace("#", serial_nr)
|
171
|
+
field = self.field3.findChild(QtWidgets.QLineEdit)
|
172
|
+
if len(field.text()) == 0:
|
173
|
+
field.setText(exchange)
|
174
|
+
|
175
|
+
|
176
|
+
def points(self):
|
177
|
+
"""Calc point"""
|
178
|
+
_mode = self.contact.get("Mode", "")
|
179
|
+
if _mode in "SSB, USB, LSB, FM, AM":
|
180
|
+
return 2
|
181
|
+
if _mode in "CW":
|
182
|
+
return 4
|
183
|
+
return 0
|
184
|
+
|
185
|
+
|
186
|
+
def show_mults(self):
|
187
|
+
"""Return display string for mults"""
|
188
|
+
# CountryPrefix, integer
|
189
|
+
|
190
|
+
us_ve_mx = 0
|
191
|
+
mm = 0
|
192
|
+
dx = 0
|
193
|
+
|
194
|
+
sql = (
|
195
|
+
"select count(DISTINCT(NR || ':' || Mode)) as mult_count "
|
196
|
+
f"from dxlog where ContestNR = {self.database.current_contest} and typeof(NR) = 'text';"
|
197
|
+
)
|
198
|
+
result = self.database.exec_sql(sql)
|
199
|
+
if result:
|
200
|
+
us_ve_mx = result.get("mult_count", 0)
|
201
|
+
|
202
|
+
# MM
|
203
|
+
sql = (
|
204
|
+
"select count(DISTINCT(NR || ':' || Mode)) as mult_count "
|
205
|
+
f"from dxlog where ContestNR = {self.database.current_contest} "
|
206
|
+
"and typeof(NR) = 'integer' "
|
207
|
+
"and call like '%/MM';"
|
208
|
+
)
|
209
|
+
result = self.database.exec_sql(sql)
|
210
|
+
if result:
|
211
|
+
mm = result.get("mult_count", 0)
|
212
|
+
|
213
|
+
# DX
|
214
|
+
sql = (
|
215
|
+
"select count(DISTINCT(CountryPrefix || ':' || Mode)) as mult_count "
|
216
|
+
f"from dxlog where ContestNR = {self.database.current_contest} "
|
217
|
+
"and typeof(NR) = 'integer' "
|
218
|
+
"and call not like '%/MM';"
|
219
|
+
)
|
220
|
+
result = self.database.exec_sql(sql)
|
221
|
+
if result:
|
222
|
+
dx = result.get("mult_count", 0)
|
223
|
+
|
224
|
+
return us_ve_mx + mm + dx
|
225
|
+
|
226
|
+
|
227
|
+
def show_qso(self):
|
228
|
+
"""Return qso count"""
|
229
|
+
result = self.database.fetch_qso_count()
|
230
|
+
if result:
|
231
|
+
return int(result.get("qsos", 0))
|
232
|
+
return 0
|
233
|
+
|
234
|
+
|
235
|
+
def calc_score(self):
|
236
|
+
"""Return calculated score"""
|
237
|
+
# Multipliers: Each US State + DC once per mode
|
238
|
+
_points = get_points(self)
|
239
|
+
_mults = show_mults(self)
|
240
|
+
_power_mult = 1
|
241
|
+
# if self.contest_settings.get("PowerCategory", "") == "QRP":
|
242
|
+
# _power_mult = 2
|
243
|
+
return _points * _power_mult * _mults
|
244
|
+
|
245
|
+
|
246
|
+
def adif(self):
|
247
|
+
"""Call the generate ADIF function"""
|
248
|
+
gen_adif(self, cabrillo_name)
|
249
|
+
|
250
|
+
|
251
|
+
def cabrillo(self):
|
252
|
+
"""Generates Cabrillo file. Maybe."""
|
253
|
+
# https://www.cqwpx.com/cabrillo.htm
|
254
|
+
logger.debug("******Cabrillo*****")
|
255
|
+
logger.debug("Station: %s", f"{self.station}")
|
256
|
+
logger.debug("Contest: %s", f"{self.contest_settings}")
|
257
|
+
now = datetime.datetime.now()
|
258
|
+
date_time = now.strftime("%Y-%m-%d_%H-%M-%S")
|
259
|
+
filename = (
|
260
|
+
str(Path.home())
|
261
|
+
+ "/"
|
262
|
+
+ f"{self.station.get('Call').upper()}_{cabrillo_name}_{date_time}.log"
|
263
|
+
)
|
264
|
+
logger.debug("%s", filename)
|
265
|
+
log = self.database.fetch_all_contacts_asc()
|
266
|
+
try:
|
267
|
+
with open(filename, "w", encoding="ascii") as file_descriptor:
|
268
|
+
print("START-OF-LOG: 3.0", end="\r\n", file=file_descriptor)
|
269
|
+
print(
|
270
|
+
f"CREATED-BY: Not1MM v{__version__}",
|
271
|
+
end="\r\n",
|
272
|
+
file=file_descriptor,
|
273
|
+
)
|
274
|
+
print(
|
275
|
+
f"CONTEST: {cabrillo_name}",
|
276
|
+
end="\r\n",
|
277
|
+
file=file_descriptor,
|
278
|
+
)
|
279
|
+
print(
|
280
|
+
f"CALLSIGN: {self.station.get('Call','')}",
|
281
|
+
end="\r\n",
|
282
|
+
file=file_descriptor,
|
283
|
+
)
|
284
|
+
print(
|
285
|
+
f"LOCATION: {self.station.get('ARRLSection', '')}",
|
286
|
+
end="\r\n",
|
287
|
+
file=file_descriptor,
|
288
|
+
)
|
289
|
+
# print(
|
290
|
+
# f"ARRL-SECTION: {self.pref.get('section', '')}",
|
291
|
+
# end="\r\n",
|
292
|
+
# file=file_descriptor,
|
293
|
+
# )
|
294
|
+
print(
|
295
|
+
f"CATEGORY-OPERATOR: {self.contest_settings.get('OperatorCategory','')}",
|
296
|
+
end="\r\n",
|
297
|
+
file=file_descriptor,
|
298
|
+
)
|
299
|
+
print(
|
300
|
+
f"CATEGORY-ASSISTED: {self.contest_settings.get('AssistedCategory','')}",
|
301
|
+
end="\r\n",
|
302
|
+
file=file_descriptor,
|
303
|
+
)
|
304
|
+
print(
|
305
|
+
f"CATEGORY-BAND: {self.contest_settings.get('BandCategory','')}",
|
306
|
+
end="\r\n",
|
307
|
+
file=file_descriptor,
|
308
|
+
)
|
309
|
+
print(
|
310
|
+
f"CATEGORY-MODE: {self.contest_settings.get('ModeCategory','')}",
|
311
|
+
end="\r\n",
|
312
|
+
file=file_descriptor,
|
313
|
+
)
|
314
|
+
print(
|
315
|
+
f"CATEGORY-TRANSMITTER: {self.contest_settings.get('TransmitterCategory','')}",
|
316
|
+
end="\r\n",
|
317
|
+
file=file_descriptor,
|
318
|
+
)
|
319
|
+
if self.contest_settings.get("OverlayCategory", "") != "N/A":
|
320
|
+
print(
|
321
|
+
f"CATEGORY-OVERLAY: {self.contest_settings.get('OverlayCategory','')}",
|
322
|
+
end="\r\n",
|
323
|
+
file=file_descriptor,
|
324
|
+
)
|
325
|
+
print(
|
326
|
+
f"GRID-LOCATOR: {self.station.get('GridSquare','')}",
|
327
|
+
end="\r\n",
|
328
|
+
file=file_descriptor,
|
329
|
+
)
|
330
|
+
# print(
|
331
|
+
# f"CATEGORY: {None}",
|
332
|
+
# end="\r\n",
|
333
|
+
# file=file_descriptor,
|
334
|
+
# )
|
335
|
+
print(
|
336
|
+
f"CATEGORY-POWER: {self.contest_settings.get('PowerCategory','')}",
|
337
|
+
end="\r\n",
|
338
|
+
file=file_descriptor,
|
339
|
+
)
|
340
|
+
|
341
|
+
print(
|
342
|
+
f"CLAIMED-SCORE: {calc_score(self)}",
|
343
|
+
end="\r\n",
|
344
|
+
file=file_descriptor,
|
345
|
+
)
|
346
|
+
print(
|
347
|
+
f"OPERATORS: {self.contest_settings.get('Operators','')}",
|
348
|
+
end="\r\n",
|
349
|
+
file=file_descriptor,
|
350
|
+
)
|
351
|
+
print(
|
352
|
+
f"NAME: {self.station.get('Name', '')}",
|
353
|
+
end="\r\n",
|
354
|
+
file=file_descriptor,
|
355
|
+
)
|
356
|
+
print(
|
357
|
+
f"ADDRESS: {self.station.get('Street1', '')}",
|
358
|
+
end="\r\n",
|
359
|
+
file=file_descriptor,
|
360
|
+
)
|
361
|
+
print(
|
362
|
+
f"ADDRESS-CITY: {self.station.get('City', '')}",
|
363
|
+
end="\r\n",
|
364
|
+
file=file_descriptor,
|
365
|
+
)
|
366
|
+
print(
|
367
|
+
f"ADDRESS-STATE-PROVINCE: {self.station.get('State', '')}",
|
368
|
+
end="\r\n",
|
369
|
+
file=file_descriptor,
|
370
|
+
)
|
371
|
+
print(
|
372
|
+
f"ADDRESS-POSTALCODE: {self.station.get('Zip', '')}",
|
373
|
+
end="\r\n",
|
374
|
+
file=file_descriptor,
|
375
|
+
)
|
376
|
+
print(
|
377
|
+
f"ADDRESS-COUNTRY: {self.station.get('Country', '')}",
|
378
|
+
end="\r\n",
|
379
|
+
file=file_descriptor,
|
380
|
+
)
|
381
|
+
print(
|
382
|
+
f"EMAIL: {self.station.get('Email', '')}",
|
383
|
+
end="\r\n",
|
384
|
+
file=file_descriptor,
|
385
|
+
)
|
386
|
+
for contact in log:
|
387
|
+
the_date_and_time = contact.get("TS", "")
|
388
|
+
themode = contact.get("Mode", "")
|
389
|
+
if themode == "LSB" or themode == "USB":
|
390
|
+
themode = "PH"
|
391
|
+
frequency = str(int(contact.get("Freq", "0"))).rjust(5)
|
392
|
+
|
393
|
+
loggeddate = the_date_and_time[:10]
|
394
|
+
loggedtime = the_date_and_time[11:13] + the_date_and_time[14:16]
|
395
|
+
print(
|
396
|
+
f"QSO: {frequency} {themode} {loggeddate} {loggedtime} "
|
397
|
+
f"{contact.get('StationPrefix', '').ljust(13)} "
|
398
|
+
f"{str(contact.get('SNT', '')).ljust(3)} "
|
399
|
+
f"{str(contact.get('SentNr', '')).ljust(6)} "
|
400
|
+
f"{contact.get('Call', '').ljust(13)} "
|
401
|
+
f"{str(contact.get('RCV', '')).ljust(3)} "
|
402
|
+
f"{str(contact.get('NR', '')).ljust(6)}",
|
403
|
+
end="\r\n",
|
404
|
+
file=file_descriptor,
|
405
|
+
)
|
406
|
+
print("END-OF-LOG:", end="\r\n", file=file_descriptor)
|
407
|
+
except IOError as exception:
|
408
|
+
logger.critical("cabrillo: IO error: %s, writing to %s", exception, filename)
|
409
|
+
return
|
410
|
+
|
411
|
+
|
412
|
+
def recalculate_mults(self):
|
413
|
+
"""Recalculates multipliers after change in logged qso."""
|
not1mm/plugins/arrl_dx_cw.py
CHANGED
not1mm/plugins/arrl_dx_ssb.py
CHANGED
not1mm/plugins/arrl_ss_cw.py
CHANGED
@@ -137,7 +137,10 @@ def points(self):
|
|
137
137
|
|
138
138
|
def show_mults(self):
|
139
139
|
"""Return display string for mults"""
|
140
|
-
sql =
|
140
|
+
sql = (
|
141
|
+
"select count(DISTINCT(Sect)) as mults from dxlog ",
|
142
|
+
f"where ContestNR = {self.database.current_contest};",
|
143
|
+
)
|
141
144
|
result = self.database.exec_sql(sql)
|
142
145
|
return int(result.get("mults", 0))
|
143
146
|
|
not1mm/plugins/arrl_ss_phone.py
CHANGED
@@ -137,7 +137,10 @@ def points(self):
|
|
137
137
|
|
138
138
|
def show_mults(self):
|
139
139
|
"""Return display string for mults"""
|
140
|
-
sql =
|
140
|
+
sql = (
|
141
|
+
"select count(DISTINCT(Sect)) as mults from dxlog ",
|
142
|
+
f"where ContestNR = {self.database.current_contest};",
|
143
|
+
)
|
141
144
|
result = self.database.exec_sql(sql)
|
142
145
|
return int(result.get("mults", 0))
|
143
146
|
|