not1mm 25.5.25__py3-none-any.whl → 25.5.26.1__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.
@@ -217,6 +217,11 @@
217
217
  <string>ARI 40 80</string>
218
218
  </property>
219
219
  </item>
220
+ <item>
221
+ <property name="text">
222
+ <string>ARI DX</string>
223
+ </property>
224
+ </item>
220
225
  <item>
221
226
  <property name="text">
222
227
  <string>ARRL 10M</string>
not1mm/lib/version.py CHANGED
@@ -1,4 +1,3 @@
1
1
  """It's the version"""
2
2
 
3
- __version__ = "25.5.25"
4
-
3
+ __version__ = "25.5.26.1"
not1mm/logwindow.py CHANGED
@@ -900,12 +900,13 @@ class LogWindow(QDockWidget):
900
900
  self.get_column("UUID"),
901
901
  QtWidgets.QTableWidgetItem(str(log_item.get("ID", ""))),
902
902
  )
903
- self.generalLog.blockSignals(False)
904
- self.focusedLog.blockSignals(False)
903
+
905
904
  self.generalLog.resizeColumnsToContents()
906
905
  self.generalLog.resizeRowsToContents()
907
906
  self.focusedLog.resizeColumnsToContents()
908
907
  self.focusedLog.resizeRowsToContents()
908
+ self.generalLog.blockSignals(False)
909
+ self.focusedLog.blockSignals(False)
909
910
 
910
911
  def show_like_calls(self, call: str) -> None:
911
912
  """
@@ -0,0 +1,689 @@
1
+ """ARI International DX Contest"""
2
+
3
+ # pylint: disable=invalid-name, c-extension-no-member, unused-import, line-too-long
4
+ # pyright: ignore[reportUndefinedVariable]
5
+ # pylance: disable=reportUndefinedVariable
6
+ # ruff: noqa: F821
7
+ # ruff: noqa: F401
8
+
9
+ # Status: Active
10
+ # Geographic Focus: Worldwide
11
+ # Participation: Worldwide
12
+ # Awards: Worldwide
13
+ # Mode: Phone, CW, RTTY
14
+ # Bands: 80, 40, 20, 15, 10m
15
+ # Classes: Single Op (CW/SSB/RTTY/Mixed)(Low/High)
16
+ # Single Op Overlays (Italian only): (Rookie/Youth)
17
+ # Multi-Single
18
+ # Multi-Multi
19
+ # SWL
20
+ # Max power: HP: >100 watts
21
+ # LP: 100 watts
22
+ # Exchange: I: RS(T) + 2-letter province
23
+ # non-I: RS(T) + Serial No.
24
+ # Work stations: Once per mode per band
25
+ # QSO Points: 0 points per QSO with same country
26
+ # 1 point per QSO with different country same continent
27
+ # 3 points per QSO with different continent
28
+ # 10 points per QSO with I/IS0/IT9 stations
29
+ # Multipliers: Each Italian province once per band
30
+ # Each DXCC country once per band
31
+ # Score Calculation: Total score = total QSO points x total mults
32
+ # E-mail logs to: (none)
33
+ # Upload log at: https://www.ari.it/contest-hf/ari-international/log-upload.html
34
+ # Mail logs to: (none)
35
+ # Find rules at: https://www.ari.it/
36
+ # Cabrillo name: ARI-DX
37
+
38
+
39
+ import datetime
40
+ import logging
41
+ import platform
42
+
43
+ from pathlib import Path
44
+
45
+ from PyQt6 import QtWidgets
46
+
47
+ from not1mm.lib.ham_utility import get_logged_band
48
+ from not1mm.lib.plugin_common import gen_adif
49
+ from not1mm.lib.version import __version__
50
+
51
+ logger = logging.getLogger(__name__)
52
+
53
+ EXCHANGE_HINT = "Prov or '#'"
54
+
55
+ name = "ARI International DX"
56
+ cabrillo_name = "ARI-DX"
57
+ mode = "BOTH" # CW SSB BOTH RTTY
58
+
59
+ columns = [
60
+ "YYYY-MM-DD HH:MM:SS",
61
+ "Call",
62
+ "Freq",
63
+ "Mode",
64
+ "Snt",
65
+ "Rcv",
66
+ "SentNr",
67
+ "RcvNr",
68
+ "PTS",
69
+ ]
70
+
71
+ advance_on_space = [True, True, True, True, True]
72
+
73
+ # 1 once per contest, 2 work each band, 3 each band/mode, 4 no dupe checking
74
+ dupe_type = 3
75
+
76
+
77
+ def init_contest(self):
78
+ """setup plugin"""
79
+ set_tab_next(self)
80
+ set_tab_prev(self)
81
+ interface(self)
82
+ self.next_field = self.other_2
83
+
84
+
85
+ def interface(self):
86
+ """Setup user interface"""
87
+ self.field1.show()
88
+ self.field2.show()
89
+ self.field3.show()
90
+ self.field4.show()
91
+ self.snt_label.setText("SNT")
92
+ self.field1.setAccessibleName("RST Sent")
93
+ self.exch_label.setText("Prov or SN")
94
+ self.field4.setAccessibleName("Province or Serial Number")
95
+
96
+
97
+ def reset_label(self): # pylint: disable=unused-argument
98
+ """reset label after field cleared"""
99
+
100
+
101
+ def set_tab_next(self):
102
+ """Set TAB Advances"""
103
+ self.tab_next = {
104
+ self.callsign: self.sent,
105
+ self.sent: self.receive,
106
+ self.receive: self.other_1,
107
+ self.other_1: self.other_2,
108
+ self.other_2: self.callsign,
109
+ }
110
+
111
+
112
+ def set_tab_prev(self):
113
+ """Set TAB Advances"""
114
+ self.tab_prev = {
115
+ self.callsign: self.other_2,
116
+ self.sent: self.callsign,
117
+ self.receive: self.sent,
118
+ self.other_1: self.receive,
119
+ self.other_2: self.other_1,
120
+ }
121
+
122
+
123
+ def set_contact_vars(self):
124
+ """Contest Specific"""
125
+ self.contact["SNT"] = self.sent.text()
126
+ self.contact["RCV"] = self.receive.text()
127
+ self.contact["NR"] = self.other_2.text().upper()
128
+ self.contact["SentNr"] = self.other_1.text()
129
+
130
+
131
+ def predupe(self): # pylint: disable=unused-argument
132
+ """called after callsign entered"""
133
+
134
+
135
+ def prefill(self):
136
+ """Fill sentnr"""
137
+ result = self.database.get_serial()
138
+ serial_nr = str(result.get("serial_nr", "1")).zfill(3)
139
+ if serial_nr == "None":
140
+ serial_nr = "001"
141
+
142
+ exchange = self.contest_settings.get("SentExchange", "").replace("#", serial_nr)
143
+ if len(self.other_1.text()) == 0:
144
+ self.other_1.setText(exchange)
145
+
146
+
147
+ def points(self) -> int:
148
+ """Calc point"""
149
+
150
+ # QSO Points: 0 points per QSO with same country
151
+ # 1 point per QSO with different country same continent
152
+ # 3 points per QSO with different continent
153
+ # 10 points per QSO with I/IS0/IT9 stations
154
+
155
+ if self.contact_is_dupe > 0:
156
+ return 0
157
+
158
+ result = self.cty_lookup(self.station.get("Call", ""))
159
+ if result:
160
+ for item in result.items():
161
+ mycountry = item[1].get("primary_pfx", "")
162
+ # myentity = item[1].get("entity", "")
163
+ mycontinent = item[1].get("continent", "")
164
+
165
+ result = self.cty_lookup(self.contact.get("Call", ""))
166
+
167
+ if result:
168
+ for item in result.items():
169
+ hiscountry = item[1].get("primary_pfx", "")
170
+ # hisentity = item[1].get("entity", "")
171
+ hiscontinent = item[1].get("continent", "")
172
+
173
+ _points = 0
174
+
175
+ if mycountry == hiscountry:
176
+ _points = 0
177
+ if mycountry != hiscountry and mycontinent == hiscontinent:
178
+ _points = 1
179
+ if mycontinent != hiscontinent:
180
+ _points = 3
181
+ if hiscountry in ("I", "IS0", "IT9"):
182
+ _points = 10
183
+
184
+ return _points
185
+
186
+
187
+ def show_mults(self):
188
+ """Return display string for mults"""
189
+
190
+ # Multipliers: Each Italian province once per band
191
+ # Each DXCC country once per band
192
+
193
+ _country = 0
194
+ _province = 0
195
+
196
+ sql = (
197
+ "select count(DISTINCT(NR || ':' || Band)) as mult_count from dxlog "
198
+ f"where ContestNR = {self.database.current_contest} and typeof(NR) = 'text';"
199
+ )
200
+ result = self.database.exec_sql(sql)
201
+ if result:
202
+ _province = result.get("mult_count", 0)
203
+
204
+ sql = (
205
+ "select count(DISTINCT(CountryPrefix || ':' || Band)) as cb_count from dxlog "
206
+ f"where ContestNR = {self.database.current_contest} and CountryPrefix NOT in ('I', 'IS');"
207
+ )
208
+ result2 = self.database.exec_sql(sql)
209
+ if result2:
210
+ _country = int(result2.get("cb_count", 0))
211
+
212
+ return _country + _province
213
+
214
+
215
+ def show_qso(self):
216
+ """Return qso count"""
217
+ result = self.database.fetch_qso_count()
218
+ if result:
219
+ return int(result.get("qsos", 0))
220
+ return 0
221
+
222
+
223
+ def calc_score(self):
224
+ """Return calculated score"""
225
+ result = self.database.fetch_points()
226
+ if result is not None:
227
+ score = result.get("Points", "0")
228
+ if score is None:
229
+ score = "0"
230
+ contest_points = int(score)
231
+ mults = int(show_mults(self))
232
+ return contest_points * mults
233
+ return 0
234
+
235
+
236
+ def adif(self):
237
+ """Call the generate ADIF function"""
238
+ gen_adif(self, cabrillo_name, cabrillo_name)
239
+
240
+
241
+ def output_cabrillo_line(line_to_output, ending, file_descriptor, file_encoding):
242
+ """"""
243
+ print(
244
+ line_to_output.encode(file_encoding, errors="ignore").decode(),
245
+ end=ending,
246
+ file=file_descriptor,
247
+ )
248
+
249
+
250
+ def cabrillo(self, file_encoding):
251
+ """Generates Cabrillo file. Maybe."""
252
+ # https://www.cw160.com/cabrillo.htm
253
+ logger.debug("******Cabrillo*****")
254
+ logger.debug("Station: %s", f"{self.station}")
255
+ logger.debug("Contest: %s", f"{self.contest_settings}")
256
+ now = datetime.datetime.now()
257
+ date_time = now.strftime("%Y-%m-%d_%H-%M-%S")
258
+ filename = (
259
+ str(Path.home())
260
+ + "/"
261
+ + f"{self.station.get('Call', '').upper()}_{cabrillo_name}_{date_time}.log"
262
+ )
263
+ logger.debug("%s", filename)
264
+ log = self.database.fetch_all_contacts_asc()
265
+ try:
266
+ with open(filename, "w", encoding=file_encoding, newline="") as file_descriptor:
267
+ output_cabrillo_line(
268
+ "START-OF-LOG: 3.0",
269
+ "\r\n",
270
+ file_descriptor,
271
+ file_encoding,
272
+ )
273
+ output_cabrillo_line(
274
+ f"CREATED-BY: Not1MM v{__version__}",
275
+ "\r\n",
276
+ file_descriptor,
277
+ file_encoding,
278
+ )
279
+ output_cabrillo_line(
280
+ f"CONTEST: {cabrillo_name}",
281
+ "\r\n",
282
+ file_descriptor,
283
+ file_encoding,
284
+ )
285
+ if self.station.get("Club", ""):
286
+ output_cabrillo_line(
287
+ f"CLUB: {self.station.get('Club', '').upper()}",
288
+ "\r\n",
289
+ file_descriptor,
290
+ file_encoding,
291
+ )
292
+ output_cabrillo_line(
293
+ f"CALLSIGN: {self.station.get('Call','')}",
294
+ "\r\n",
295
+ file_descriptor,
296
+ file_encoding,
297
+ )
298
+ output_cabrillo_line(
299
+ f"LOCATION: {self.station.get('ARRLSection', '')}",
300
+ "\r\n",
301
+ file_descriptor,
302
+ file_encoding,
303
+ )
304
+ output_cabrillo_line(
305
+ f"CATEGORY-OPERATOR: {self.contest_settings.get('OperatorCategory','')}",
306
+ "\r\n",
307
+ file_descriptor,
308
+ file_encoding,
309
+ )
310
+ output_cabrillo_line(
311
+ f"CATEGORY-ASSISTED: {self.contest_settings.get('AssistedCategory','')}",
312
+ "\r\n",
313
+ file_descriptor,
314
+ file_encoding,
315
+ )
316
+ output_cabrillo_line(
317
+ f"CATEGORY-BAND: {self.contest_settings.get('BandCategory','')}",
318
+ "\r\n",
319
+ file_descriptor,
320
+ file_encoding,
321
+ )
322
+ mode = self.contest_settings.get("ModeCategory", "")
323
+ if mode in ["SSB+CW", "SSB+CW+DIGITAL"]:
324
+ mode = "MIXED"
325
+ output_cabrillo_line(
326
+ f"CATEGORY-MODE: {mode}",
327
+ "\r\n",
328
+ file_descriptor,
329
+ file_encoding,
330
+ )
331
+ output_cabrillo_line(
332
+ f"CATEGORY-TRANSMITTER: {self.contest_settings.get('TransmitterCategory','')}",
333
+ "\r\n",
334
+ file_descriptor,
335
+ file_encoding,
336
+ )
337
+ if self.contest_settings.get("OverlayCategory", "") != "N/A":
338
+ output_cabrillo_line(
339
+ f"CATEGORY-OVERLAY: {self.contest_settings.get('OverlayCategory','')}",
340
+ "\r\n",
341
+ file_descriptor,
342
+ file_encoding,
343
+ )
344
+ output_cabrillo_line(
345
+ f"GRID-LOCATOR: {self.station.get('GridSquare','')}",
346
+ "\r\n",
347
+ file_descriptor,
348
+ file_encoding,
349
+ )
350
+ output_cabrillo_line(
351
+ f"CATEGORY-POWER: {self.contest_settings.get('PowerCategory','')}",
352
+ "\r\n",
353
+ file_descriptor,
354
+ file_encoding,
355
+ )
356
+
357
+ output_cabrillo_line(
358
+ f"CLAIMED-SCORE: {calc_score(self)}",
359
+ "\r\n",
360
+ file_descriptor,
361
+ file_encoding,
362
+ )
363
+ ops = f"@{self.station.get('Call','')}"
364
+ list_of_ops = self.database.get_ops()
365
+ for op in list_of_ops:
366
+ ops += f", {op.get('Operator', '')}"
367
+ output_cabrillo_line(
368
+ f"OPERATORS: {ops}",
369
+ "\r\n",
370
+ file_descriptor,
371
+ file_encoding,
372
+ )
373
+ output_cabrillo_line(
374
+ f"NAME: {self.station.get('Name', '')}",
375
+ "\r\n",
376
+ file_descriptor,
377
+ file_encoding,
378
+ )
379
+ output_cabrillo_line(
380
+ f"ADDRESS: {self.station.get('Street1', '')}",
381
+ "\r\n",
382
+ file_descriptor,
383
+ file_encoding,
384
+ )
385
+ output_cabrillo_line(
386
+ f"ADDRESS-CITY: {self.station.get('City', '')}",
387
+ "\r\n",
388
+ file_descriptor,
389
+ file_encoding,
390
+ )
391
+ output_cabrillo_line(
392
+ f"ADDRESS-STATE-PROVINCE: {self.station.get('State', '')}",
393
+ "\r\n",
394
+ file_descriptor,
395
+ file_encoding,
396
+ )
397
+ output_cabrillo_line(
398
+ f"ADDRESS-POSTALCODE: {self.station.get('Zip', '')}",
399
+ "\r\n",
400
+ file_descriptor,
401
+ file_encoding,
402
+ )
403
+ output_cabrillo_line(
404
+ f"ADDRESS-COUNTRY: {self.station.get('Country', '')}",
405
+ "\r\n",
406
+ file_descriptor,
407
+ file_encoding,
408
+ )
409
+ output_cabrillo_line(
410
+ f"EMAIL: {self.station.get('Email', '')}",
411
+ "\r\n",
412
+ file_descriptor,
413
+ file_encoding,
414
+ )
415
+ for contact in log:
416
+ the_date_and_time = contact.get("TS", "")
417
+ themode = contact.get("Mode", "")
418
+ if themode == "LSB" or themode == "USB":
419
+ themode = "PH"
420
+ if themode == "RTTY":
421
+ themode = "RY"
422
+ frequency = str(int(contact.get("Freq", "0"))).rjust(5)
423
+
424
+ loggeddate = the_date_and_time[:10]
425
+ loggedtime = the_date_and_time[11:13] + the_date_and_time[14:16]
426
+ output_cabrillo_line(
427
+ f"QSO: {frequency} {themode} {loggeddate} {loggedtime} "
428
+ f"{contact.get('StationPrefix', '').ljust(13)} "
429
+ f"{str(contact.get('SNT', '')).ljust(3)} "
430
+ f"{str(contact.get('SentNr', '')).upper().ljust(6)} "
431
+ f"{contact.get('Call', '').ljust(13)} "
432
+ f"{str(contact.get('RCV', '')).ljust(3)} "
433
+ f"{str(contact.get('NR', '')).upper().ljust(6)}",
434
+ "\r\n",
435
+ file_descriptor,
436
+ file_encoding,
437
+ )
438
+ output_cabrillo_line("END-OF-LOG:", "\r\n", file_descriptor, file_encoding)
439
+ self.show_message_box(f"Cabrillo saved to: {filename}")
440
+ except IOError as exception:
441
+ logger.critical("cabrillo: IO error: %s, writing to %s", exception, filename)
442
+ self.show_message_box(f"Error saving Cabrillo: {exception} {filename}")
443
+ return
444
+
445
+
446
+ def trigger_update(self):
447
+ """Triggers the log window to update."""
448
+ cmd = {}
449
+ cmd["cmd"] = "UPDATELOG"
450
+ if self.log_window:
451
+ self.log_window.msg_from_main(cmd)
452
+
453
+
454
+ def recalculate_mults(self):
455
+ """Recalculates multipliers after change in logged qso."""
456
+
457
+
458
+ def process_esm(self, new_focused_widget=None, with_enter=False):
459
+ """ESM State Machine"""
460
+
461
+ # self.pref["run_state"]
462
+
463
+ # -----===== Assigned F-Keys =====-----
464
+ # self.esm_dict["CQ"]
465
+ # self.esm_dict["EXCH"]
466
+ # self.esm_dict["QRZ"]
467
+ # self.esm_dict["AGN"]
468
+ # self.esm_dict["HISCALL"]
469
+ # self.esm_dict["MYCALL"]
470
+ # self.esm_dict["QSOB4"]
471
+
472
+ # ----==== text fields ====----
473
+ # self.callsign
474
+ # self.sent
475
+ # self.receive
476
+ # self.other_1
477
+ # self.other_2
478
+
479
+ if new_focused_widget is not None:
480
+ self.current_widget = self.inputs_dict.get(new_focused_widget)
481
+
482
+ # print(f"checking esm {self.current_widget=} {with_enter=} {self.pref.get("run_state")=}")
483
+
484
+ for a_button in [
485
+ self.esm_dict["CQ"],
486
+ self.esm_dict["EXCH"],
487
+ self.esm_dict["QRZ"],
488
+ self.esm_dict["AGN"],
489
+ self.esm_dict["HISCALL"],
490
+ self.esm_dict["MYCALL"],
491
+ self.esm_dict["QSOB4"],
492
+ ]:
493
+ if a_button is not None:
494
+ self.restore_button_color(a_button)
495
+
496
+ buttons_to_send = []
497
+
498
+ if self.pref.get("run_state"):
499
+ if self.current_widget == "callsign":
500
+ if len(self.callsign.text()) < 3:
501
+ self.make_button_green(self.esm_dict["CQ"])
502
+ buttons_to_send.append(self.esm_dict["CQ"])
503
+ elif len(self.callsign.text()) > 2:
504
+ self.make_button_green(self.esm_dict["HISCALL"])
505
+ self.make_button_green(self.esm_dict["EXCH"])
506
+ buttons_to_send.append(self.esm_dict["HISCALL"])
507
+ buttons_to_send.append(self.esm_dict["EXCH"])
508
+
509
+ elif self.current_widget in ["other_2"]:
510
+ if self.other_2.text() == "":
511
+ self.make_button_green(self.esm_dict["AGN"])
512
+ buttons_to_send.append(self.esm_dict["AGN"])
513
+ else:
514
+ self.make_button_green(self.esm_dict["QRZ"])
515
+ buttons_to_send.append(self.esm_dict["QRZ"])
516
+ buttons_to_send.append("LOGIT")
517
+
518
+ if with_enter is True and bool(len(buttons_to_send)):
519
+ for button in buttons_to_send:
520
+ if button:
521
+ if button == "LOGIT":
522
+ self.save_contact()
523
+ continue
524
+ self.process_function_key(button)
525
+ else:
526
+ if self.current_widget == "callsign":
527
+ if len(self.callsign.text()) > 2:
528
+ self.make_button_green(self.esm_dict["MYCALL"])
529
+ buttons_to_send.append(self.esm_dict["MYCALL"])
530
+
531
+ elif self.current_widget in ["other_2"]:
532
+ if self.other_2.text() == "":
533
+ self.make_button_green(self.esm_dict["AGN"])
534
+ buttons_to_send.append(self.esm_dict["AGN"])
535
+ else:
536
+ self.make_button_green(self.esm_dict["EXCH"])
537
+ buttons_to_send.append(self.esm_dict["EXCH"])
538
+ buttons_to_send.append("LOGIT")
539
+
540
+ if with_enter is True and bool(len(buttons_to_send)):
541
+ for button in buttons_to_send:
542
+ if button:
543
+ if button == "LOGIT":
544
+ self.save_contact()
545
+ continue
546
+ self.process_function_key(button)
547
+
548
+
549
+ def populate_history_info_line(self):
550
+ result = self.database.fetch_call_history(self.callsign.text())
551
+ if result:
552
+ self.history_info.setText(f"{result.get('Call', '')}, {result.get('Sect', '')}")
553
+ else:
554
+ self.history_info.setText("")
555
+
556
+
557
+ def check_call_history(self):
558
+ """"""
559
+ result = self.database.fetch_call_history(self.callsign.text())
560
+ if result:
561
+ self.history_info.setText(f"{result.get('UserText','')}")
562
+ if self.other_2.text() == "":
563
+ self.other_2.setText(f"{result.get('Sect', '')}")
564
+
565
+
566
+ def set_self(the_outie):
567
+ """..."""
568
+ globals()["ALTEREGO"] = the_outie
569
+
570
+
571
+ def ft8_handler(the_packet: dict):
572
+ print(f"{the_packet=}")
573
+ """Process FT8 QSO packets
574
+ FT8
575
+ {
576
+ 'CALL': 'KE0OG',
577
+ 'GRIDSQUARE': 'DM10AT',
578
+ 'MODE': 'FT8',
579
+ 'RST_SENT': '',
580
+ 'RST_RCVD': '',
581
+ 'QSO_DATE': '20210329',
582
+ 'TIME_ON': '183213',
583
+ 'QSO_DATE_OFF': '20210329',
584
+ 'TIME_OFF': '183213',
585
+ 'BAND': '20M',
586
+ 'FREQ': '14.074754',
587
+ 'STATION_CALLSIGN': 'K6GTE',
588
+ 'MY_GRIDSQUARE': 'DM13AT',
589
+ 'CONTEST_ID': 'ARRL-FIELD-DAY',
590
+ 'SRX_STRING': '1D UT',
591
+ 'CLASS': '1D',
592
+ 'ARRL_SECT': 'UT'
593
+ }
594
+ FlDigi
595
+ {
596
+ 'CALL': 'K5TUS',
597
+ 'MODE': 'RTTY',
598
+ 'FREQ': '14.068415',
599
+ 'BAND': '20M',
600
+ 'QSO_DATE': '20250103',
601
+ 'TIME_ON': '2359',
602
+ 'QSO_DATE_OFF': '20250103',
603
+ 'TIME_OFF': '2359',
604
+ 'NAME': '',
605
+ 'QTH': '',
606
+ 'STATE': 'ORG',
607
+ 'VE_PROV': '',
608
+ 'COUNTRY': 'USA',
609
+ 'RST_SENT': '599',
610
+ 'RST_RCVD': '599',
611
+ 'TX_PWR': '0',
612
+ 'CNTY': '',
613
+ 'DXCC': '',
614
+ 'CQZ': '5',
615
+ 'IOTA': '',
616
+ 'CONT': '',
617
+ 'ITUZ': '',
618
+ 'GRIDSQUARE': '',
619
+ 'QSLRDATE': '',
620
+ 'QSLSDATE': '',
621
+ 'EQSLRDATE': '',
622
+ 'EQSLSDATE': '',
623
+ 'LOTWRDATE': '',
624
+ 'LOTWSDATE': '',
625
+ 'QSL_VIA': '',
626
+ 'NOTES': '',
627
+ 'SRX': '',
628
+ 'STX': '000',
629
+ 'SRX_STRING': '',
630
+ 'STX_STRING': 'CA',
631
+
632
+
633
+ 'SRX': '666',
634
+ 'STX': '000',
635
+ 'SRX_STRING': '',
636
+ 'STX_STRING': 'CA',
637
+
638
+ 'SRX': '004', 'STX': '000', 'SRX_STRING': '', 'STX_STRING': '#',
639
+
640
+ 'CLASS': '',
641
+ 'ARRL_SECT': '',
642
+ 'OPERATOR': 'K6GTE',
643
+ 'STATION_CALLSIGN': 'K6GTE',
644
+ 'MY_GRIDSQUARE': 'DM13AT',
645
+ 'MY_CITY': 'ANAHEIM, CA',
646
+ 'CHECK': '',
647
+ 'AGE': '',
648
+ 'TEN_TEN': '',
649
+ 'CWSS_PREC': '',
650
+ 'CWSS_SECTION': '',
651
+ 'CWSS_SERNO': '',
652
+ 'CWSS_CHK': ''
653
+ }
654
+
655
+ """
656
+ logger.debug(f"{the_packet=}")
657
+ if ALTEREGO is not None: # type: ignore
658
+ ALTEREGO.callsign.setText(the_packet.get("CALL")) # type: ignore
659
+ ALTEREGO.contact["Call"] = the_packet.get("CALL", "") # type: ignore
660
+ ALTEREGO.contact["SNT"] = the_packet.get("RST_SENT", "599") # type: ignore
661
+ ALTEREGO.contact["RCV"] = the_packet.get("RST_RCVD", "599") # type: ignore
662
+
663
+ sent_string = the_packet.get("STX_STRING", "")
664
+ if sent_string != "":
665
+ ALTEREGO.contact["SentNr"] = sent_string # type: ignore
666
+ ALTEREGO.other_1.setText(str(sent_string)) # type: ignore
667
+ else:
668
+ ALTEREGO.contact["SentNr"] = the_packet.get("STX", "000") # type: ignore
669
+ ALTEREGO.other_1.setText(str(the_packet.get("STX", "000"))) # type: ignore
670
+
671
+ rx_string = the_packet.get("STATE", "")
672
+ if rx_string != "":
673
+ ALTEREGO.contact["NR"] = rx_string # type: ignore
674
+ ALTEREGO.other_2.setText(str(rx_string)) # type: ignore
675
+ else:
676
+ ALTEREGO.contact["NR"] = the_packet.get("SRX", "000") # type: ignore
677
+ ALTEREGO.other_2.setText(str(the_packet.get("SRX", "000"))) # type: ignore
678
+
679
+ ALTEREGO.contact["Mode"] = the_packet.get("MODE", "ERR") # type: ignore
680
+ ALTEREGO.contact["Freq"] = round(float(the_packet.get("FREQ", "0.0")) * 1000, 2) # type: ignore
681
+ ALTEREGO.contact["QSXFreq"] = round( # type: ignore
682
+ float(the_packet.get("FREQ", "0.0")) * 1000, 2
683
+ )
684
+ ALTEREGO.contact["Band"] = get_logged_band( # type: ignore
685
+ str(int(float(the_packet.get("FREQ", "0.0")) * 1000000))
686
+ )
687
+ logger.debug(f"{ALTEREGO.contact=}") # type: ignore
688
+
689
+ ALTEREGO.save_contact() # type: ignore
@@ -174,7 +174,7 @@ def show_mults(self):
174
174
 
175
175
  sql = (
176
176
  "select count(DISTINCT(NR || ':' || Band || ':' || Mode)) as mult_count from dxlog "
177
- "where ContestNR = {self.database.current_contest} and typeof(NR) = 'text';"
177
+ f"where ContestNR = {self.database.current_contest} and typeof(NR) = 'text';"
178
178
  )
179
179
  result = self.database.exec_sql(sql)
180
180
  if result:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: not1mm
3
- Version: 25.5.25
3
+ Version: 25.5.26.1
4
4
  Summary: NOT1MM Logger
5
5
  Author-email: Michael Bridak <michael.bridak@gmail.com>
6
6
  License: GPL-3.0-or-later
@@ -219,6 +219,8 @@ generated, 'cause I'm lazy, list of those who've submitted PR's.
219
219
  - 10 10 Spring CW
220
220
  - 10 10 Summer Phone
221
221
  - 10 10 Winter Phone
222
+ - ARI 40 80
223
+ - ARI DX
222
224
  - ARRL 10M
223
225
  - ARRL 160M
224
226
  - ARRL DX CW, SSB
@@ -259,6 +261,7 @@ generated, 'cause I'm lazy, list of those who've submitted PR's.
259
261
 
260
262
  ## Recent Changes
261
263
 
264
+ - [25-5-26] Add ARI DX contest, Fix Canada Day mults.
262
265
  - [25-5-25] Added {PREVNR} macro to resend last logged serial number.
263
266
  - Add Bandmap mode indicators for CW, FT*, SSB, Beacons.
264
267
  - Made tuning with the VFO knob smoother.
@@ -898,8 +901,26 @@ blue rectangle shows the receivers bandwidth if one is reported.
898
901
 
899
902
  ![Bandmap Window](https://github.com/mbridak/not1mm/raw/master/pic/VFO_and_bandwidth_markers.png)
900
903
 
901
- Clicked on spots now tune the radio and set the callsign field. Previously
902
- worked calls are displayed in red.
904
+ Clicking on a spots tunes the radio to the spot frequency and sets the callsign field.
905
+
906
+ Previously worked calls are displayed in Red.
907
+
908
+ Callsigns that were marked with CTRL-M to work later are displayed in a Yellow-ish color.
909
+
910
+ In between the spots call and time is now a little icon to visually tell you what kind of spot it is.
911
+
912
+ ![Bandmap Icons](https://github.com/mbridak/not1mm/raw/master/pic/bandmap_icons.png)
913
+
914
+ - ○ CW
915
+ - ⦿ FT*
916
+ - ⌾ RTTY
917
+ - 🗼 Beacons
918
+ - @ Everything else
919
+
920
+ Secondary Icons:
921
+
922
+ - [P] POTA
923
+ - [S] SOTA
903
924
 
904
925
  ### The Check Partial Window
905
926
 
@@ -927,7 +948,9 @@ This window contains QSO rates and counts.
927
948
 
928
949
  You can control the VFO on a remote rig by following the directions listed in
929
950
  the link below. It's a small hardware project with a BOM of under $20, and
930
- consisting of two parts.
951
+ consisting of two parts. The VFO knob is now detectable on MacOS. I've made the
952
+ operation of the knob smoother by having the knob ignore frequency updates from
953
+ the radio while it's in rotation.
931
954
 
932
955
  1. Making the [VFO](https://github.com/mbridak/not1mm/blob/master/usb_vfo_knob/vfo.md)...
933
956
  2. Then... `Window`>`VFO`
@@ -3,7 +3,7 @@ not1mm/__main__.py,sha256=FZZGObcnSJEzEFj7a2K_-DPJUivmDS2tV5boPVudSJs,169592
3
3
  not1mm/bandmap.py,sha256=0JmZ32UvkaPjXs2xTgowX1GLvZo5zHU_Zo9y_GL-On4,31139
4
4
  not1mm/checkwindow.py,sha256=zEHlw40j6Wr3rvKbCQf2lcezCoiZqaBqEvBjQU5aKW0,7630
5
5
  not1mm/fsutils.py,sha256=ukHKxKTeNKxKwqRaJjtzRShL4X5Xl0jRBbADyy3Ifp8,1701
6
- not1mm/logwindow.py,sha256=zpCCcyRLK40D2rcxnIJBSVVqPEmTHKCrkAcfEj5sZ54,42624
6
+ not1mm/logwindow.py,sha256=hYzpCQKkwgILFUtP5uxQXy6uU9zCB0R-aBDAUsSOPFI,42625
7
7
  not1mm/lookupservice.py,sha256=GkY_qHZfrW6XHf8upIoaG4hCFqm0fg6Ganu9ConGrIc,2628
8
8
  not1mm/radio.py,sha256=4Lysf9BY3vdtYCHwKfzO5WN7IGyh4_lKSVuQ6F4Z08g,5536
9
9
  not1mm/ratewindow.py,sha256=iBjqdOetIEX0wSwdGM89Ibt4gVlFdE-K8HQPnkVPVOg,6965
@@ -36,7 +36,7 @@ not1mm/data/k6gte.not1mm-64.png,sha256=6ku45Gq1g5ezh04F07osoKRtanb3e4kbx5XdIEh3N
36
36
  not1mm/data/logwindow.ui,sha256=vfkNdzJgFs3tTOBKLDavF2zVMvNHWOZ82fAErRi6pQY,1436
37
37
  not1mm/data/logwindowx.ui,sha256=9FzDJtLRpagvAWcDjFdB9NnvNZ4bVxdTNHy1Jit2ido,1610
38
38
  not1mm/data/main.ui,sha256=gEWmfXmqLM-DiujjnPdU-4buYJF9TQxS9gE0JlVv_4Y,65142
39
- not1mm/data/new_contest.ui,sha256=WKg2jy8jxHg2d3pZsBTcdSNObKcd0eVbO-OoW0u0uxA,25309
39
+ not1mm/data/new_contest.ui,sha256=uYEn8RU8kkGI2jUC7_gsH5HpVvJdG79cl_10OpvFCXw,25412
40
40
  not1mm/data/not1mm.html,sha256=c9-mfjMwDt4f5pySUruz2gREW33CQ2_rCddM2z5CZQo,23273
41
41
  not1mm/data/opon.ui,sha256=mC4OhoVIfR1H9IqHAKXliPMm8VOVmxSEadpsFQ7XnS4,2247
42
42
  not1mm/data/pickcontest.ui,sha256=Pbb_YEOzQfacyhIRkx-M3ZGugIIPL1KPztdwVv5c_q0,1696
@@ -120,7 +120,7 @@ not1mm/lib/plugin_common.py,sha256=D1OBjyLmX7zuSPqgTCmHwXzAKA12J_zTQItvyIem-4Y,1
120
120
  not1mm/lib/select_contest.py,sha256=WsptLuwkouIHeocJL3oZ6-eUfEnhpwdc-x7eMZ_TIVM,359
121
121
  not1mm/lib/settings.py,sha256=5xnsagH48qGeCDhfxPWW9yaXtv8wT13yoIVvYt8h_Qs,16023
122
122
  not1mm/lib/super_check_partial.py,sha256=hwT2NRwobu0PLDyw6ltmbmcAtGBD02CKGFbgGWjXMqA,2334
123
- not1mm/lib/version.py,sha256=gcUyTawJD4PIn_mBa947znnmgM9-mvfHXIEnCSo7gnM,49
123
+ not1mm/lib/version.py,sha256=yA7CdtW3TS2_La829zvpEQPRX8CKY-9FzSRHeqAinb8,50
124
124
  not1mm/lib/versiontest.py,sha256=8vDNptuBBunn-1IGkjNaquehqBYUJyjrPSF8Igmd4_Y,1286
125
125
  not1mm/plugins/10_10_fall_cw.py,sha256=oJh3JKqjOpnWElSlZpiQ631UnaOd8qra5s9bl_QoInk,14783
126
126
  not1mm/plugins/10_10_spring_cw.py,sha256=p7dSDtbFK0e6Xouw2V6swYn3VFVgHKyx4IfRWyBjMZY,14786
@@ -128,6 +128,7 @@ not1mm/plugins/10_10_summer_phone.py,sha256=NWWT5YTZN6CkPl5Jy4lCuTqHd1R_JodhsOLq
128
128
  not1mm/plugins/10_10_winter_phone.py,sha256=4xoWLbnE2di5XnUUlhsvTR__E0Z4kbhu-rcUitPMR0U,14795
129
129
  not1mm/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
130
130
  not1mm/plugins/ari_40_80.py,sha256=_CaUWEo0zJONXvxPqJKyqmStJezqxEsNxOnEdSLmxzY,15333
131
+ not1mm/plugins/ari_dx.py,sha256=GXAq9H-JrE_QZ5E4Dhkyo6v18Z4-xomAtgZOg_aTzRI,22380
131
132
  not1mm/plugins/arrl_10m.py,sha256=9p7EX2vAXVilF8y6AYHG4fXczU6g9QuMA2Pvj64pSXE,18389
132
133
  not1mm/plugins/arrl_160m.py,sha256=rdWDhmPN0h9ADTlYaRLk-5j8KVye0rUEs1tyD-kfHV0,20300
133
134
  not1mm/plugins/arrl_dx_cw.py,sha256=Bx6_PBmTHKf4l52XwLFVeR2y6F134kXbGTfEXC_1agk,18890
@@ -139,7 +140,7 @@ not1mm/plugins/arrl_ss_phone.py,sha256=PzybC--tSB7_oNLbbN9xYkMnftH-z6qgcGZUp3-JG
139
140
  not1mm/plugins/arrl_vhf_jan.py,sha256=paYrF_o1EotBRmXn_x9_hEM16SWx7sLDzoSoXcYXcCY,20201
140
141
  not1mm/plugins/arrl_vhf_jun.py,sha256=WwQ-UGFekIZj26bIbq3sLacTYMmUzBYySHhPz2APm2M,19293
141
142
  not1mm/plugins/arrl_vhf_sep.py,sha256=kq5Rncru74G9B76VwfXMeTaF9AL8hq-1vw9ZMYmJmvM,19326
142
- not1mm/plugins/canada_day.py,sha256=89aGXm4S9PjKL9FYm3z7BMFRz--MugQQilwQnzLJvv0,15770
143
+ not1mm/plugins/canada_day.py,sha256=L8pBKcfZGUycBfRS3g9PfeavNIL8CTRAUYk-fVMXDoU,15771
143
144
  not1mm/plugins/cq_160_cw.py,sha256=bmHtxVcIWsqmgqpMCMso7DCBERtAr9fIKIjgymSKtms,18711
144
145
  not1mm/plugins/cq_160_ssb.py,sha256=9KKDmmapETEebm1azfEzUWk1NyW3TBnYtBlFIPZYHBs,18754
145
146
  not1mm/plugins/cq_wpx_cw.py,sha256=F5lLuXumrviNHnNEk377OKeEJCnv_j9vnjHEcV70gFc,18249
@@ -182,9 +183,9 @@ not1mm/plugins/ukeidx.py,sha256=0ABGW7_9Ui0Rgr8mkPBxOJokAIerM1a4-HWnl6VsnV8,1910
182
183
  not1mm/plugins/vhf_sprint.py,sha256=a9QFTpv8XUbZ_GLjdVCh7svykFa-gXOWwKFZ6MD3uQM,19289
183
184
  not1mm/plugins/weekly_rtty.py,sha256=C8Xs3Q5UgSYx-mFFar8BVARWtmqlyrbeC98Ubzb4UN8,20128
184
185
  not1mm/plugins/winter_field_day.py,sha256=hmAMgkdqIXtnCNyUp8J9Bb8liN8wj10wps6ROuG-Bok,15284
185
- not1mm-25.5.25.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
186
- not1mm-25.5.25.dist-info/METADATA,sha256=LMao9elh21fHypET3g4kblWcGFyjDg5z0A1LSOMY2J0,41254
187
- not1mm-25.5.25.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
188
- not1mm-25.5.25.dist-info/entry_points.txt,sha256=pMcZk_0dxFgLkcUkF0Q874ojpwOmF3OL6EKw9LgvocM,47
189
- not1mm-25.5.25.dist-info/top_level.txt,sha256=0YmTxEcDzQlzXub-lXASvoLpg_mt1c2thb5cVkDf5J4,7
190
- not1mm-25.5.25.dist-info/RECORD,,
186
+ not1mm-25.5.26.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
187
+ not1mm-25.5.26.1.dist-info/METADATA,sha256=OCl5-STfmrP_sLIxfT1KFyEysSZ7-hu_nx8VN8aSYTY,41911
188
+ not1mm-25.5.26.1.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
189
+ not1mm-25.5.26.1.dist-info/entry_points.txt,sha256=pMcZk_0dxFgLkcUkF0Q874ojpwOmF3OL6EKw9LgvocM,47
190
+ not1mm-25.5.26.1.dist-info/top_level.txt,sha256=0YmTxEcDzQlzXub-lXASvoLpg_mt1c2thb5cVkDf5J4,7
191
+ not1mm-25.5.26.1.dist-info/RECORD,,