not1mm 24.8.20__py3-none-any.whl → 24.9.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
not1mm/__main__.py CHANGED
@@ -23,6 +23,7 @@ import threading
23
23
  import uuid
24
24
 
25
25
  from json import dumps, loads
26
+ from json.decoder import JSONDecodeError
26
27
  from pathlib import Path
27
28
  from shutil import copyfile
28
29
 
@@ -35,9 +36,9 @@ except OSError as exception:
35
36
  print("portaudio is not installed")
36
37
  sd = None
37
38
  from PyQt6 import QtCore, QtGui, QtWidgets, uic
38
- from PyQt6.QtCore import QDir, Qt, QThread, QSettings
39
- from PyQt6.QtGui import QFontDatabase, QColorConstants, QPalette, QColor
40
- from PyQt6.QtWidgets import QFileDialog
39
+ from PyQt6.QtCore import QDir, Qt, QThread, QSettings, QCoreApplication
40
+ from PyQt6.QtGui import QFontDatabase, QColorConstants, QPalette, QColor, QPixmap
41
+ from PyQt6.QtWidgets import QFileDialog, QSplashScreen
41
42
 
42
43
  from not1mm.lib.about import About
43
44
  from not1mm.lib.cwinterface import CW
@@ -186,8 +187,7 @@ class MainWindow(QtWidgets.QMainWindow):
186
187
  )
187
188
  self.setCorner(Qt.Corner.TopLeftCorner, Qt.DockWidgetArea.LeftDockWidgetArea)
188
189
  self.setCorner(Qt.Corner.BottomLeftCorner, Qt.DockWidgetArea.LeftDockWidgetArea)
189
- data_path = fsutils.APP_DATA_PATH / "main.ui"
190
- uic.loadUi(data_path, self)
190
+ uic.loadUi(fsutils.APP_DATA_PATH / "main.ui", self)
191
191
  self.cw_entry.hide()
192
192
  self.leftdot.hide()
193
193
  self.rightdot.hide()
@@ -459,8 +459,15 @@ class MainWindow(QtWidgets.QMainWindow):
459
459
  self.setWindowIcon(
460
460
  QtGui.QIcon(str(fsutils.APP_DATA_PATH / "k6gte.not1mm-32.png"))
461
461
  )
462
- with open(fsutils.APP_DATA_PATH / "cty.json", "rt", encoding="utf-8") as c_file:
463
- self.ctyfile = loads(c_file.read())
462
+
463
+ try:
464
+ with open(
465
+ fsutils.APP_DATA_PATH / "cty.json", "rt", encoding="utf-8"
466
+ ) as c_file:
467
+ self.ctyfile = loads(c_file.read())
468
+ except (IOError, JSONDecodeError, TypeError):
469
+ logging.CRITICAL("There was an error parsing the BigCity file.")
470
+
464
471
  self.readpreferences()
465
472
 
466
473
  self.voice_process = Voice()
@@ -491,9 +498,7 @@ class MainWindow(QtWidgets.QMainWindow):
491
498
  self.make_op_dir()
492
499
 
493
500
  self.clearinputs()
494
-
495
- if self.pref.get("contest"):
496
- self.load_contest()
501
+ self.load_contest()
497
502
  self.read_cw_macros()
498
503
 
499
504
  # Featureset for wayland
@@ -1287,10 +1292,15 @@ class MainWindow(QtWidgets.QMainWindow):
1287
1292
  if updated:
1288
1293
  cty.dump(fsutils.APP_DATA_PATH / "cty.json")
1289
1294
  self.show_message_box("cty file updated.")
1290
- with open(
1291
- fsutils.APP_DATA_PATH / "cty.json", "rt", encoding="utf-8"
1292
- ) as ctyfile:
1293
- self.ctyfile = loads(ctyfile.read())
1295
+ try:
1296
+ with open(
1297
+ fsutils.APP_DATA_PATH / "cty.json", "rt", encoding="utf-8"
1298
+ ) as ctyfile:
1299
+ self.ctyfile = loads(ctyfile.read())
1300
+ except (IOError, JSONDecodeError, TypeError) as err:
1301
+ logging.CRITICAL(
1302
+ f"There was an error {err} parsing the BigCity file."
1303
+ )
1294
1304
  else:
1295
1305
  self.show_message_box("An Error occured updating file.")
1296
1306
  else:
@@ -1898,11 +1908,14 @@ class MainWindow(QtWidgets.QMainWindow):
1898
1908
  " "
1899
1909
  )[:19]
1900
1910
  self.contact["Call"] = self.callsign.text()
1901
- self.contact["Freq"] = round(float(self.radio_state.get("vfoa", 0.0)) / 1000, 2)
1902
- self.contact["QSXFreq"] = round(
1903
- float(self.radio_state.get("vfoa", 0.0)) / 1000, 2
1904
- )
1905
- self.contact["Mode"] = self.radio_state.get("mode", "")
1911
+ if self.contact.get("Mode") not in ("FT8", "FT4"):
1912
+ self.contact["Freq"] = round(
1913
+ float(self.radio_state.get("vfoa", 0.0)) / 1000, 2
1914
+ )
1915
+ self.contact["QSXFreq"] = round(
1916
+ float(self.radio_state.get("vfoa", 0.0)) / 1000, 2
1917
+ )
1918
+ self.contact["Mode"] = self.radio_state.get("mode", "")
1906
1919
  self.contact["ContestName"] = self.contest.cabrillo_name
1907
1920
  self.contact["ContestNR"] = self.pref.get("contest", "0")
1908
1921
  self.contact["StationPrefix"] = self.station.get("Call", "")
@@ -2093,7 +2106,7 @@ class MainWindow(QtWidgets.QMainWindow):
2093
2106
 
2094
2107
  def save_settings(self) -> None:
2095
2108
  """
2096
- Save settings to database.
2109
+ Save Station settings to database.
2097
2110
 
2098
2111
  Parameters
2099
2112
  ----------
@@ -2322,7 +2335,7 @@ class MainWindow(QtWidgets.QMainWindow):
2322
2335
  with open(fsutils.CONFIG_FILE, "wt", encoding="utf-8") as file_descriptor:
2323
2336
  file_descriptor.write(dumps(self.pref, indent=4))
2324
2337
  # logger.info("writing: %s", self.pref)
2325
- except IOError as exception:
2338
+ except (IOError, TypeError, ValueError) as exception:
2326
2339
  logger.critical("writepreferences: %s", exception)
2327
2340
 
2328
2341
  def readpreferences(self) -> None:
@@ -2344,7 +2357,12 @@ class MainWindow(QtWidgets.QMainWindow):
2344
2357
  with open(
2345
2358
  fsutils.CONFIG_FILE, "rt", encoding="utf-8"
2346
2359
  ) as file_descriptor:
2347
- self.pref = loads(file_descriptor.read())
2360
+ try:
2361
+ self.pref = loads(file_descriptor.read())
2362
+ except (JSONDecodeError, TypeError):
2363
+ logging.CRITICAL(
2364
+ "There was an error parsing the preference file."
2365
+ )
2348
2366
  logger.info("%s", self.pref)
2349
2367
  else:
2350
2368
  logger.info("No preference file. Writing preference.")
@@ -2354,7 +2372,7 @@ class MainWindow(QtWidgets.QMainWindow):
2354
2372
  self.pref = self.pref_ref.copy()
2355
2373
  file_descriptor.write(dumps(self.pref, indent=4))
2356
2374
  logger.info("%s", self.pref)
2357
- except IOError as exception:
2375
+ except (IOError, TypeError, ValueError) as exception:
2358
2376
  logger.critical("Error: %s", exception)
2359
2377
 
2360
2378
  self.look_up = None
@@ -3197,10 +3215,14 @@ class MainWindow(QtWidgets.QMainWindow):
3197
3215
  else:
3198
3216
  macro_file = "ssbmacros.txt"
3199
3217
  if not (fsutils.USER_DATA_PATH / macro_file).exists():
3200
- logger.debug("read_cw_macros: copying default macro file.")
3201
- copyfile(
3202
- fsutils.APP_DATA_PATH / macro_file, fsutils.USER_DATA_PATH / macro_file
3203
- )
3218
+ logger.debug("copying default macro file.")
3219
+ try:
3220
+ copyfile(
3221
+ fsutils.APP_DATA_PATH / macro_file,
3222
+ fsutils.USER_DATA_PATH / macro_file,
3223
+ )
3224
+ except IOError as err:
3225
+ logger.critical(f"Error {err} copying macro file.")
3204
3226
  try:
3205
3227
  fsutils.openFileWithOS(fsutils.USER_DATA_PATH / macro_file)
3206
3228
  except FileNotFoundError | PermissionError | OSError as err:
@@ -3221,22 +3243,26 @@ class MainWindow(QtWidgets.QMainWindow):
3221
3243
  macro_file = "ssbmacros.txt"
3222
3244
 
3223
3245
  if not (fsutils.USER_DATA_PATH / macro_file).exists():
3224
- logger.debug("read_cw_macros: copying default macro file.")
3225
- copyfile(
3226
- fsutils.APP_DATA_PATH / macro_file, fsutils.USER_DATA_PATH / macro_file
3227
- )
3228
- with open(
3229
- fsutils.USER_DATA_PATH / macro_file, "r", encoding="utf-8"
3230
- ) as file_descriptor:
3231
- for line in file_descriptor:
3232
- try:
3246
+ logger.debug("copying default macro file.")
3247
+ try:
3248
+ copyfile(
3249
+ fsutils.APP_DATA_PATH / macro_file,
3250
+ fsutils.USER_DATA_PATH / macro_file,
3251
+ )
3252
+ except IOError as err:
3253
+ logger.critical(f"Error {err} copying macro file.")
3254
+ try:
3255
+ with open(
3256
+ fsutils.USER_DATA_PATH / macro_file, "r", encoding="utf-8"
3257
+ ) as file_descriptor:
3258
+ for line in file_descriptor:
3233
3259
  mode, fkey, buttonname, cwtext = line.split("|")
3234
3260
  if mode.strip().upper() == "R" and self.pref.get("run_state"):
3235
3261
  self.fkeys[fkey.strip()] = (buttonname.strip(), cwtext.strip())
3236
3262
  if mode.strip().upper() != "R" and not self.pref.get("run_state"):
3237
3263
  self.fkeys[fkey.strip()] = (buttonname.strip(), cwtext.strip())
3238
- except ValueError as err:
3239
- logger.info("read_cw_macros: %s", err)
3264
+ except (IOError, ValueError) as err:
3265
+ logger.info("read_cw_macros: %s", err)
3240
3266
  keys = self.fkeys.keys()
3241
3267
  if "F1" in keys:
3242
3268
  self.F1.setText(f"F1: {self.fkeys['F1'][0]}")
@@ -3398,12 +3424,24 @@ logging.basicConfig(
3398
3424
  logging.getLogger("PyQt6.uic.uiparser").setLevel("INFO")
3399
3425
  logging.getLogger("PyQt6.uic.properties").setLevel("INFO")
3400
3426
  app = QtWidgets.QApplication(sys.argv)
3427
+
3428
+ pixmap = QPixmap(f"{os.fspath(fsutils.APP_DATA_PATH)}/splash.png")
3429
+ splash = QSplashScreen(pixmap)
3430
+ splash.show()
3431
+ app.processEvents()
3432
+ splash.showMessage(
3433
+ "Starting Up",
3434
+ alignment=Qt.AlignmentFlag.AlignBottom | Qt.AlignmentFlag.AlignCenter,
3435
+ color=QColor(255, 255, 0),
3436
+ )
3437
+ QCoreApplication.processEvents()
3438
+
3401
3439
  families = load_fonts_from_dir(os.fspath(fsutils.APP_DATA_PATH))
3402
3440
  logger.info(f"font families {families}")
3403
3441
  window = MainWindow()
3404
3442
  window.callsign.setFocus()
3405
3443
  window.show()
3406
-
3444
+ splash.finish(window)
3407
3445
 
3408
3446
  if __name__ == "__main__":
3409
3447
  run()
@@ -297,6 +297,11 @@
297
297
  <string>CWT</string>
298
298
  </property>
299
299
  </item>
300
+ <item>
301
+ <property name="text">
302
+ <string>HELVETIA</string>
303
+ </property>
304
+ </item>
300
305
  <item>
301
306
  <property name="text">
302
307
  <string>ICWC MST</string>
@@ -356,7 +361,7 @@
356
361
  </property>
357
362
  <property name="time">
358
363
  <time>
359
- <hour>16</hour>
364
+ <hour>0</hour>
360
365
  <minute>0</minute>
361
366
  <second>0</second>
362
367
  </time>
not1mm/data/splash.png ADDED
Binary file
not1mm/lib/database.py CHANGED
@@ -567,7 +567,7 @@ class DataBase:
567
567
  def fetch_country_band_count(self) -> dict:
568
568
  """
569
569
  returns dict with count of unique NR.
570
- {nr_count: count}
570
+ {cb_count: count}
571
571
  """
572
572
  try:
573
573
  with sqlite3.connect(self.database) as conn:
@@ -581,6 +581,23 @@ class DataBase:
581
581
  logger.debug("%s", exception)
582
582
  return {}
583
583
 
584
+ def fetch_country_count(self) -> dict:
585
+ """
586
+ Fetch count of unique countries
587
+ {dxcc_count: count}
588
+ """
589
+ try:
590
+ with sqlite3.connect(self.database) as conn:
591
+ conn.row_factory = self.row_factory
592
+ cursor = conn.cursor()
593
+ cursor.execute(
594
+ f"select count(DISTINCT(CountryPrefix)) as dxcc_count from dxlog where ContestNR = {self.current_contest};"
595
+ )
596
+ return cursor.fetchone()
597
+ except sqlite3.OperationalError as exception:
598
+ logger.debug("%s", exception)
599
+ return {}
600
+
584
601
  def fetch_arrldx_country_band_count(self) -> dict:
585
602
  """
586
603
  returns dict with count of unique NR.
@@ -869,14 +886,14 @@ class DataBase:
869
886
  logger.debug("%s", exception)
870
887
  return {}
871
888
 
872
- def fetch_mult1_count(self) -> dict:
889
+ def fetch_mult_count(self, mult: int) -> dict:
873
890
  """return QSO count"""
874
891
  try:
875
892
  with sqlite3.connect(self.database) as conn:
876
893
  conn.row_factory = self.row_factory
877
894
  cursor = conn.cursor()
878
895
  cursor.execute(
879
- f"select count(*) as count from dxlog where IsMultiplier1 = 1 and ContestNR = {self.current_contest};"
896
+ f"select count(*) as count from dxlog where IsMultiplier{mult} = 1 and ContestNR = {self.current_contest};"
880
897
  )
881
898
  return cursor.fetchone()
882
899
  except sqlite3.OperationalError as exception:
not1mm/lib/ham_utility.py CHANGED
@@ -373,3 +373,29 @@ def distance_with_latlon(grid1: str, lat2: float, lon2: float) -> float:
373
373
  logger.debug("lat1:%d lon1:%d lat2:%d lon2:%d", lat1, lon1, lat2, lon2)
374
374
  # lat2, lon2 = gridtolatlon(grid2)
375
375
  return round(haversine(lon1, lat1, lon2, lat2))
376
+
377
+
378
+ def parse_udc(filename: str) -> dict:
379
+ """
380
+ simply parses a n1mm style udc file and returns a dict with key value pairs.
381
+ """
382
+
383
+ udc_contest = {}
384
+ the_good_stuff = False
385
+
386
+ try:
387
+ with open(filename, "r", encoding="utf-8") as file_descriptor:
388
+ for line in file_descriptor:
389
+ if "[CONTEST]" in line.upper():
390
+ the_good_stuff = True
391
+ continue
392
+ if "=" in line and the_good_stuff is True:
393
+ try:
394
+ key, value = line.split("=")
395
+ udc_contest[key.strip()] = value.strip()
396
+ except ValueError:
397
+ ...
398
+ except FileNotFoundError:
399
+ logger.debug("UDC file not found.")
400
+ return {}
401
+ return udc_contest
not1mm/lib/version.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """It's the version"""
2
2
 
3
- __version__ = "24.8.20"
3
+ __version__ = "24.9.3"
@@ -8,6 +8,7 @@ import logging
8
8
  from pathlib import Path
9
9
  from PyQt6 import QtWidgets
10
10
 
11
+ from not1mm.lib.ham_utility import get_logged_band
11
12
  from not1mm.lib.plugin_common import gen_adif, get_points
12
13
  from not1mm.lib.version import __version__
13
14
 
@@ -114,7 +115,7 @@ def points(self):
114
115
  _mode = self.contact.get("Mode", "")
115
116
  if _mode in "SSB, USB, LSB, FM, AM":
116
117
  return 1
117
- if _mode in "CW, RTTY":
118
+ if _mode in "CW, RTTY, FT8":
118
119
  return 2
119
120
  return 0
120
121
 
@@ -295,8 +296,10 @@ def cabrillo(self):
295
296
  for contact in log:
296
297
  the_date_and_time = contact.get("TS", "")
297
298
  themode = contact.get("Mode", "")
298
- if themode == "LSB" or themode == "USB":
299
+ if themode in ("LSB", "USB"):
299
300
  themode = "PH"
301
+ if themode in ("FT8", "FT4"):
302
+ themode = "DG"
300
303
  frequency = str(int(contact.get("Freq", "0"))).rjust(5)
301
304
 
302
305
  loggeddate = the_date_and_time[:10]
@@ -362,7 +365,15 @@ def ft8_handler(the_packet: dict):
362
365
  ALTEREGO.contact["RCV"] = ALTEREGO.receive.text()
363
366
  ALTEREGO.contact["Exchange1"] = the_packet.get("CLASS", "ERR")
364
367
  ALTEREGO.contact["Sect"] = the_packet.get("ARRL_SECT", "ERR")
365
- ALTEREGO.contact["Mode"] = "FT8"
368
+ ALTEREGO.contact["Mode"] = the_packet.get("MODE", "ERR")
369
+ ALTEREGO.contact["Freq"] = round(float(the_packet.get("FREQ", "0.0")) * 1000, 2)
370
+ ALTEREGO.contact["QSXFreq"] = round(
371
+ float(the_packet.get("FREQ", "0.0")) * 1000, 2
372
+ )
373
+ ALTEREGO.contact["Band"] = get_logged_band(
374
+ str(int(float(the_packet.get("FREQ", "0.0")) * 1000000))
375
+ )
366
376
  ALTEREGO.other_1.setText(the_packet.get("CLASS", "ERR"))
367
377
  ALTEREGO.other_2.setText(the_packet.get("ARRL_SECT", "ERR"))
368
378
  print(f"\n{ALTEREGO.contact=}\n")
379
+ ALTEREGO.save_contact()
@@ -177,7 +177,7 @@ def points(self):
177
177
 
178
178
  def show_mults(self):
179
179
  """Return display string for mults"""
180
- result = self.database.fetch_mult1_count()
180
+ result = self.database.fetch_mult_count(1)
181
181
  count = result.get("count", 0)
182
182
  return count
183
183
 
@@ -198,7 +198,7 @@ def calc_score(self):
198
198
  if score is None:
199
199
  score = "0"
200
200
  contest_points = int(score)
201
- result = self.database.fetch_mult1_count()
201
+ result = self.database.fetch_mult_count(1)
202
202
  mults = int(result.get("count", 0))
203
203
  return contest_points * mults
204
204
  return 0
@@ -177,7 +177,7 @@ def points(self):
177
177
 
178
178
  def show_mults(self):
179
179
  """Return display string for mults"""
180
- result = self.database.fetch_mult1_count()
180
+ result = self.database.fetch_mult_count(1)
181
181
  count = result.get("count", 0)
182
182
  return count
183
183
 
@@ -198,7 +198,7 @@ def calc_score(self):
198
198
  if score is None:
199
199
  score = "0"
200
200
  contest_points = int(score)
201
- result = self.database.fetch_mult1_count()
201
+ result = self.database.fetch_mult_count(1)
202
202
  mults = int(result.get("count", 0))
203
203
  return contest_points * mults
204
204
  return 0