not1mm 24.4.15__py3-none-any.whl → 24.4.24__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
@@ -37,7 +37,7 @@ except OSError as exception:
37
37
  sd = None
38
38
  import soundfile as sf
39
39
  from PyQt6 import QtCore, QtGui, QtWidgets, uic
40
- from PyQt6.QtCore import QDir, Qt
40
+ from PyQt6.QtCore import QDir, Qt, QThread
41
41
  from PyQt6.QtGui import QFontDatabase, QColorConstants
42
42
  from PyQt6.QtWidgets import QFileDialog
43
43
 
@@ -75,11 +75,7 @@ from not1mm.logwindow import LogWindow
75
75
  from not1mm.checkwindow import CheckWindow
76
76
  from not1mm.bandmap import BandMapWindow
77
77
  from not1mm.vfo import VfoWindow
78
-
79
- CTYFILE = {}
80
-
81
- with open(fsutils.APP_DATA_PATH / "cty.json", "rt", encoding="utf-8") as c_file:
82
- CTYFILE = loads(c_file.read())
78
+ from not1mm.radio import Radio
83
79
 
84
80
  poll_time = datetime.datetime.now()
85
81
 
@@ -111,6 +107,7 @@ class MainWindow(QtWidgets.QMainWindow):
111
107
  The main window
112
108
  """
113
109
 
110
+ ctyfile = {}
114
111
  pref_ref = {
115
112
  "sounddevice": "default",
116
113
  "useqrz": False,
@@ -190,6 +187,9 @@ class MainWindow(QtWidgets.QMainWindow):
190
187
  text_color = QColorConstants.Black
191
188
  current_palette = None
192
189
 
190
+ radio_thread = QThread()
191
+
192
+ rig_control = None
193
193
  log_window = None
194
194
  check_window = None
195
195
  bandmap_window = None
@@ -476,6 +476,8 @@ class MainWindow(QtWidgets.QMainWindow):
476
476
  self.setWindowIcon(
477
477
  QtGui.QIcon(str(fsutils.APP_DATA_PATH / "k6gte.not1mm-32.png"))
478
478
  )
479
+ with open(fsutils.APP_DATA_PATH / "cty.json", "rt", encoding="utf-8") as c_file:
480
+ self.ctyfile = loads(c_file.read())
479
481
  self.readpreferences()
480
482
  self.dbname = fsutils.USER_DATA_PATH / self.pref.get(
481
483
  "current_database", "ham.db"
@@ -1340,7 +1342,7 @@ class MainWindow(QtWidgets.QMainWindow):
1340
1342
  with open(
1341
1343
  fsutils.APP_DATA_PATH / "cty.json", "rt", encoding="utf-8"
1342
1344
  ) as ctyfile:
1343
- globals()["CTYFILE"] = loads(ctyfile.read())
1345
+ self.ctyfile = loads(ctyfile.read())
1344
1346
  else:
1345
1347
  self.show_message_box("An Error occured updating file.")
1346
1348
  else:
@@ -1589,7 +1591,9 @@ class MainWindow(QtWidgets.QMainWindow):
1589
1591
  callsign = callsign.upper()
1590
1592
  for count in reversed(range(len(callsign))):
1591
1593
  searchitem = callsign[: count + 1]
1592
- result = {key: val for key, val in CTYFILE.items() if key == searchitem}
1594
+ result = {
1595
+ key: val for key, val in self.ctyfile.items() if key == searchitem
1596
+ }
1593
1597
  if not result:
1594
1598
  continue
1595
1599
  if result.get(searchitem).get("exact_match"):
@@ -2489,29 +2493,48 @@ class MainWindow(QtWidgets.QMainWindow):
2489
2493
  self.setDarkMode(False)
2490
2494
  self.actionDark_Mode_2.setChecked(False)
2491
2495
 
2492
- self.rig_control = None
2496
+ try:
2497
+ if self.radio_thread.isRunning():
2498
+ self.rig_control.time_to_quit = True
2499
+ self.radio_thread.quit()
2500
+ self.radio_thread.wait(1000)
2501
+
2502
+ except (RuntimeError, AttributeError):
2503
+ ...
2493
2504
 
2494
2505
  if self.pref.get("useflrig", False):
2495
2506
  logger.debug(
2496
2507
  "Using flrig: %s",
2497
2508
  f"{self.pref.get('CAT_ip')} {self.pref.get('CAT_port')}",
2498
2509
  )
2499
- self.rig_control = CAT(
2510
+ self.rig_control = Radio(
2500
2511
  "flrig",
2501
2512
  self.pref.get("CAT_ip", "127.0.0.1"),
2502
2513
  int(self.pref.get("CAT_port", 12345)),
2503
2514
  )
2515
+ self.rig_control.moveToThread(self.radio_thread)
2516
+ self.radio_thread.started.connect(self.rig_control.run)
2517
+ self.radio_thread.finished.connect(self.rig_control.deleteLater)
2518
+ self.rig_control.poll_callback.connect(self.poll_radio)
2519
+ self.radio_thread.start()
2520
+ # self.rig_control.delta = 1
2504
2521
 
2505
2522
  if self.pref.get("userigctld", False):
2506
2523
  logger.debug(
2507
2524
  "Using rigctld: %s",
2508
2525
  f"{self.pref.get('CAT_ip')} {self.pref.get('CAT_port')}",
2509
2526
  )
2510
- self.rig_control = CAT(
2527
+ self.rig_control = Radio(
2511
2528
  "rigctld",
2512
2529
  self.pref.get("CAT_ip", "127.0.0.1"),
2513
2530
  int(self.pref.get("CAT_port", 4532)),
2514
2531
  )
2532
+ self.rig_control.moveToThread(self.radio_thread)
2533
+ self.radio_thread.started.connect(self.rig_control.run)
2534
+ self.radio_thread.finished.connect(self.rig_control.deleteLater)
2535
+ self.rig_control.poll_callback.connect(self.poll_radio)
2536
+ self.radio_thread.start()
2537
+ # self.rig_control.delta = 1
2515
2538
 
2516
2539
  if self.pref.get("cwtype", 0) == 0:
2517
2540
  self.cw = None
@@ -3173,81 +3196,67 @@ class MainWindow(QtWidgets.QMainWindow):
3173
3196
  logger.debug("Destination: %s", str(destination_file))
3174
3197
  destination_file.write_bytes(child.read_bytes())
3175
3198
 
3176
- def poll_radio(self) -> None:
3177
- """
3178
- Poll radio for VFO, mode, bandwidth.
3179
- Send state via multicast.
3199
+ def poll_radio(self, the_dict):
3200
+ """catch"""
3201
+ self.set_radio_icon(0)
3202
+ print(f"{the_dict=}")
3203
+ info_dirty = False
3204
+ vfo = the_dict.get("vfoa", "")
3205
+ mode = the_dict.get("mode", "")
3206
+ bw = the_dict.get("bw", "")
3207
+ online = the_dict.get("online", False)
3208
+
3209
+ if online is False:
3210
+ self.set_radio_icon(1)
3211
+ else:
3212
+ self.set_radio_icon(2)
3180
3213
 
3181
- Parameters
3182
- ----------
3183
- None
3214
+ if mode == "CW":
3215
+ self.setmode(mode)
3216
+ if mode == "LSB" or mode == "USB":
3217
+ self.setmode("SSB")
3218
+ if mode == "RTTY":
3219
+ self.setmode("RTTY")
3184
3220
 
3185
- Returns
3186
- -------
3187
- None
3188
- """
3221
+ if vfo == "":
3222
+ return
3223
+ if self.radio_state.get("vfoa") != vfo:
3224
+ info_dirty = True
3225
+ self.radio_state["vfoa"] = vfo
3226
+ band = getband(str(vfo))
3227
+ self.radio_state["band"] = band
3228
+ self.contact["Band"] = get_logged_band(str(vfo))
3229
+ self.set_band_indicator(band)
3189
3230
 
3190
- self.set_radio_icon(0)
3191
- if self.rig_control:
3192
- if self.rig_control.online is False:
3193
- self.set_radio_icon(1)
3194
- self.rig_control.reinit()
3195
- if self.rig_control.online:
3196
- self.set_radio_icon(2)
3197
- info_dirty = False
3198
- vfo = self.rig_control.get_vfo()
3199
- mode = self.rig_control.get_mode()
3200
- bw = self.rig_control.get_bw()
3201
-
3202
- if mode == "CW":
3203
- self.setmode(mode)
3204
- if mode == "LSB" or mode == "USB":
3205
- self.setmode("SSB")
3206
- if mode == "RTTY":
3207
- self.setmode("RTTY")
3208
-
3209
- if vfo == "":
3210
- return
3211
- if self.radio_state.get("vfoa") != vfo:
3212
- info_dirty = True
3213
- self.radio_state["vfoa"] = vfo
3214
- band = getband(str(vfo))
3215
- self.radio_state["band"] = band
3216
- self.contact["Band"] = get_logged_band(str(vfo))
3217
- self.set_band_indicator(band)
3218
-
3219
- if self.radio_state.get("mode") != mode:
3220
- info_dirty = True
3221
- self.radio_state["mode"] = mode
3222
-
3223
- if self.radio_state.get("bw") != bw:
3224
- info_dirty = True
3225
- self.radio_state["bw"] = bw
3226
-
3227
- if datetime.datetime.now() > globals()["poll_time"] or info_dirty:
3228
- logger.debug("VFO: %s MODE: %s BW: %s", vfo, mode, bw)
3229
- self.set_window_title()
3230
- cmd = {}
3231
- cmd["cmd"] = "RADIO_STATE"
3232
- cmd["station"] = platform.node()
3233
- cmd["band"] = band
3234
- cmd["vfoa"] = vfo
3235
- cmd["mode"] = mode
3236
- cmd["bw"] = bw
3237
- self.multicast_interface.send_as_json(cmd)
3238
- if self.n1mm:
3239
- if self.n1mm.send_radio_packets:
3240
- self.n1mm.radio_info["Freq"] = vfo[:-1]
3241
- self.n1mm.radio_info["TXFreq"] = vfo[:-1]
3242
- self.n1mm.radio_info["Mode"] = mode
3243
- self.n1mm.radio_info["OpCall"] = self.current_op
3244
- self.n1mm.radio_info["IsRunning"] = str(
3245
- self.pref.get("run_state", False)
3246
- )
3247
- self.n1mm.send_radio()
3248
- globals()[
3249
- "poll_time"
3250
- ] = datetime.datetime.now() + datetime.timedelta(seconds=10)
3231
+ if self.radio_state.get("mode") != mode:
3232
+ info_dirty = True
3233
+ self.radio_state["mode"] = mode
3234
+
3235
+ if self.radio_state.get("bw") != bw:
3236
+ info_dirty = True
3237
+ self.radio_state["bw"] = bw
3238
+
3239
+ if info_dirty:
3240
+ logger.debug("VFO: %s MODE: %s BW: %s", vfo, mode, bw)
3241
+ self.set_window_title()
3242
+ cmd = {}
3243
+ cmd["cmd"] = "RADIO_STATE"
3244
+ cmd["station"] = platform.node()
3245
+ cmd["band"] = band
3246
+ cmd["vfoa"] = vfo
3247
+ cmd["mode"] = mode
3248
+ cmd["bw"] = bw
3249
+ self.multicast_interface.send_as_json(cmd)
3250
+ if self.n1mm:
3251
+ if self.n1mm.send_radio_packets:
3252
+ self.n1mm.radio_info["Freq"] = vfo[:-1]
3253
+ self.n1mm.radio_info["TXFreq"] = vfo[:-1]
3254
+ self.n1mm.radio_info["Mode"] = mode
3255
+ self.n1mm.radio_info["OpCall"] = self.current_op
3256
+ self.n1mm.radio_info["IsRunning"] = str(
3257
+ self.pref.get("run_state", False)
3258
+ )
3259
+ self.n1mm.send_radio()
3251
3260
 
3252
3261
  def edit_cw_macros(self) -> None:
3253
3262
  """
@@ -3447,7 +3456,7 @@ def run() -> None:
3447
3456
  f"Resolved OS file system paths: MODULE_PATH {fsutils.MODULE_PATH}, USER_DATA_PATH {fsutils.USER_DATA_PATH}, CONFIG_PATH {fsutils.CONFIG_PATH}"
3448
3457
  )
3449
3458
  install_icons()
3450
- timer.start(250)
3459
+ # timer.start(250)
3451
3460
  sys.exit(app.exec())
3452
3461
 
3453
3462
 
@@ -3478,8 +3487,8 @@ y = window.pref.get("window_y", -1)
3478
3487
  window.setGeometry(x, y, width, height)
3479
3488
  window.callsign.setFocus()
3480
3489
  window.show()
3481
- timer = QtCore.QTimer()
3482
- timer.timeout.connect(window.poll_radio)
3490
+ # timer = QtCore.QTimer()
3491
+ # timer.timeout.connect(window.poll_radio)
3483
3492
 
3484
3493
  if __name__ == "__main__":
3485
3494
  run()
not1mm/checkwindow.py CHANGED
@@ -35,8 +35,9 @@ class CheckWindow(QDockWidget):
35
35
  dxcLayout: QVBoxLayout = None
36
36
  qsoLayout: QVBoxLayout = None
37
37
 
38
- character_remove_color = "#cc3333"
39
- character_add_color = "#3333cc"
38
+ character_remove_color = "#dd3333"
39
+ character_add_color = "#3333dd"
40
+ character_match_color = "#33dd33"
40
41
 
41
42
  masterScrollWidget: QWidget = None
42
43
 
@@ -162,7 +163,7 @@ class CheckWindow(QDockWidget):
162
163
  None
163
164
  """
164
165
  while self.multicast_interface.server_udp.hasPendingDatagrams():
165
- logger.error("Got multicast ")
166
+ logger.debug("Got multicast ")
166
167
  json_data = self.multicast_interface.read_datagram_as_json()
167
168
 
168
169
  if json_data.get("station", "") != platform.node():
@@ -283,6 +284,8 @@ class CheckWindow(QDockWidget):
283
284
  elif tag == "insert" or tag == "delete":
284
285
  label_text += f"<span style='background-color: {self.character_add_color};'>{call[i1:i2]}</span>"
285
286
  diff_score += max((i2 - i1), (j2 - j1)) * (len(call) - i2)
287
+ if call == self.call:
288
+ label_text = f"<span style='background-color: {self.character_match_color};'>{call}</span>"
286
289
  call_items.append((diff_score, label_text, call))
287
290
 
288
291
  call_items = sorted(call_items, key=lambda x: x[0])
not1mm/data/settings.ui CHANGED
@@ -1201,7 +1201,7 @@
1201
1201
  <string>club name</string>
1202
1202
  </property>
1203
1203
  <property name="placeholderText">
1204
- <string>Americal Radio Relay League</string>
1204
+ <string>American Radio Relay League</string>
1205
1205
  </property>
1206
1206
  </widget>
1207
1207
  </item>
not1mm/fsutils.py CHANGED
@@ -11,27 +11,21 @@ import platform
11
11
  import sys
12
12
  import subprocess
13
13
  from pathlib import Path
14
-
15
14
  from appdata import AppDataPaths
16
15
 
17
16
  WORKING_PATH = Path(os.path.dirname(os.path.abspath(__file__)))
18
-
19
17
  MODULE_PATH = WORKING_PATH
20
-
21
-
22
18
  APP_DATA_PATH = MODULE_PATH / "data"
23
- _app_paths = AppDataPaths(name="not1mm")
24
- _app_paths.setup()
25
-
26
19
  DATA_PATH = os.environ.get("XDG_DATA_HOME", str(Path.home() / ".local" / "share"))
27
20
  DATA_PATH += "/not1mm"
28
21
  USER_DATA_PATH = Path(DATA_PATH)
29
- LOG_FILE = USER_DATA_PATH / "application.log"
30
22
  _CONFIG_PATH = os.environ.get("XDG_CONFIG_HOME", str(Path.home() / ".config"))
31
23
  _CONFIG_PATH += "/not1mm"
32
24
  CONFIG_PATH = Path(_CONFIG_PATH)
33
25
  CONFIG_FILE = CONFIG_PATH / "not1mm.json"
26
+ LOG_FILE = USER_DATA_PATH / "not1mm_debug.log"
34
27
 
28
+ # Create directories if they do not exist on Linux systems
35
29
  if platform.system() not in ["Windows", "Darwin"]:
36
30
  try:
37
31
  os.mkdir(CONFIG_PATH)
@@ -42,15 +36,16 @@ if platform.system() not in ["Windows", "Darwin"]:
42
36
  except FileExistsError:
43
37
  ...
44
38
 
39
+ # Define and create directories if they do not exist on Windows or Mac systems
45
40
  if platform.system() in ["Windows", "Darwin"]:
41
+ _app_paths = AppDataPaths(name="not1mm")
42
+ _app_paths.setup()
46
43
  LOG_FILE = _app_paths.get_log_file_path(name="appplication.log")
47
44
  _DATA_PATH = Path(_app_paths.app_data_path)
48
45
  USER_DATA_PATH = _DATA_PATH
49
46
  CONFIG_PATH = USER_DATA_PATH
50
47
  CONFIG_FILE = CONFIG_PATH / "not1mm.json"
51
48
 
52
- DARK_STYLESHEET = ""
53
-
54
49
 
55
50
  def openFileWithOS(file):
56
51
  """Open a file with the default program for that OS."""
@@ -60,4 +55,3 @@ def openFileWithOS(file):
60
55
  subprocess.Popen(["open", file])
61
56
  else:
62
57
  subprocess.Popen(["xdg-open", file])
63
- # os.system(f"xdg-open {fsutils.USER_DATA_PATH / macro_file}")
not1mm/lib/ft8_watcher.py CHANGED
@@ -8,7 +8,7 @@ GPL V3
8
8
 
9
9
  from PyQt6 import QtNetwork
10
10
 
11
- # import struct
11
+ import struct
12
12
 
13
13
 
14
14
  class FT8Watcher:
@@ -86,21 +86,15 @@ class FT8Watcher:
86
86
 
87
87
  if packettype == 1: # Status
88
88
  ...
89
- # [dialfreq] = struct.unpack(">Q", payload[0:8])
90
- # modelen = self.getint(payload[8:12])
91
- # mode = payload[12 : 12 + modelen].decode()
92
- # payload = payload[12 + modelen :]
93
- # dxcalllen = self.getint(payload[0:4])
94
- # dxcall = payload[4 : 4 + dxcalllen].decode()
95
- # print(
96
- # "Status: sv:%s p:%s u:%s df:%s m:%s dxc:%s",
97
- # version,
98
- # packettype,
99
- # unique,
100
- # dialfreq,
101
- # mode,
102
- # dxcall,
103
- # )
89
+ [dialfreq] = struct.unpack(">Q", payload[0:8])
90
+ modelen = self.getint(payload[8:12])
91
+ mode = payload[12 : 12 + modelen].decode()
92
+ payload = payload[12 + modelen :]
93
+ dxcalllen = self.getint(payload[0:4])
94
+ dxcall = payload[4 : 4 + dxcalllen].decode()
95
+ print(
96
+ f"Status: sv:{version} p:{packettype} u:{unique} df:{dialfreq} m:{mode} dxc:{dxcall}"
97
+ )
104
98
 
105
99
  # if f"{dxcall}{self.band}{self.mode}" in self.dupdict:
106
100
  # self.ft8dupe = f"{dxcall} {self.band}M {self.mode} FT8 Dupe!"
not1mm/lib/settings.py CHANGED
@@ -2,7 +2,13 @@
2
2
 
3
3
  import logging
4
4
  from PyQt6 import QtWidgets, uic
5
- import sounddevice as sd
5
+
6
+ try:
7
+ import sounddevice as sd
8
+ except OSError as exception:
9
+ print(exception)
10
+ print("portaudio is not installed")
11
+ sd = None
6
12
 
7
13
 
8
14
  class Settings(QtWidgets.QDialog):
@@ -15,7 +21,10 @@ class Settings(QtWidgets.QDialog):
15
21
  uic.loadUi(app_data_path / "configuration.ui", self)
16
22
  self.buttonBox.accepted.connect(self.save_changes)
17
23
  self.preference = pref
18
- self.devices = sd.query_devices()
24
+ if sd:
25
+ self.devices = sd.query_devices()
26
+ else:
27
+ self.devices = []
19
28
  self.setup()
20
29
 
21
30
  def setup(self):
not1mm/lib/version.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """It's the version"""
2
2
 
3
- __version__ = "24.4.15"
3
+ __version__ = "24.4.24"
not1mm/radio.py ADDED
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env python3
2
+
3
+ """
4
+ Not1MM Contest logger
5
+ Email: michael.bridak@gmail.com
6
+ GPL V3
7
+ """
8
+
9
+ # pylint: disable=unused-import, c-extension-no-member, no-member, invalid-name, too-many-lines
10
+ # pylint: disable=logging-fstring-interpolation, line-too-long, no-name-in-module
11
+
12
+ import datetime
13
+
14
+ from PyQt6.QtCore import QObject, pyqtSignal
15
+ from not1mm.lib.cat_interface import CAT
16
+
17
+
18
+ class Radio(QObject):
19
+ """Radio class"""
20
+
21
+ poll_callback = pyqtSignal(dict)
22
+
23
+ cat = None
24
+ vfoa = "14030000"
25
+ mode = "CW"
26
+ bw = "500"
27
+ delta = 10
28
+ poll_time = datetime.datetime.now() + datetime.timedelta(seconds=delta)
29
+ time_to_quit = False
30
+ online = False
31
+ interface = None
32
+ host = None
33
+ port = None
34
+
35
+ def __init__(self, interface: str, host: str, port: int) -> None:
36
+ super().__init__()
37
+ """setup interface"""
38
+ self.interface = interface
39
+ self.host = host
40
+ self.port = port
41
+
42
+ def run(self):
43
+ try:
44
+ self.cat = CAT(self.interface, self.host, self.port)
45
+ except ConnectionResetError:
46
+ ...
47
+ while not self.time_to_quit:
48
+ if datetime.datetime.now() > self.poll_time:
49
+ self.poll_time = datetime.datetime.now() + datetime.timedelta(
50
+ seconds=self.delta
51
+ )
52
+ vfoa = self.cat.get_vfo()
53
+ self.online = False
54
+ if vfoa:
55
+ self.vfoa = vfoa
56
+ self.online = True
57
+ mode = self.cat.get_mode()
58
+ if mode:
59
+ self.mode = mode
60
+ self.online = True
61
+ bw = self.cat.get_bw()
62
+ if bw:
63
+ self.bw = bw
64
+ self.online = True
65
+ self.poll_callback.emit(
66
+ {
67
+ "vfoa": self.vfoa,
68
+ "mode": self.mode,
69
+ "bw": self.bw,
70
+ "online": self.online,
71
+ }
72
+ )
73
+
74
+ def set_vfo(self, vfo):
75
+ if self.cat:
76
+ self.cat.set_vfo(vfo)
77
+ self.vfoa = vfo
78
+
79
+ def set_mode(self, mode):
80
+ if self.cat:
81
+ self.cat.set_mode(mode)
82
+ self.mode = mode
83
+
84
+ def ptt_on(self):
85
+ if self.cat:
86
+ self.cat.ptt_on()
87
+
88
+ def ptt_off(self):
89
+ if self.cat:
90
+ self.cat.ptt_off()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: not1mm
3
- Version: 24.4.15
3
+ Version: 24.4.24
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
@@ -177,6 +177,8 @@ I wish to thank those who've contributed to the project.
177
177
 
178
178
  ## Recent Changes
179
179
 
180
+ - [24-4-24] Placed CAT control into a thread so disconnecting the radio wouldn't lock up the interface.
181
+ - [24-4-17] Trap OSError if no sound device. Stop fsutils/appdata from creating useless .not1mm and .username folder structures on Linux platforms.
180
182
  - [24-4-15] checkwindow.py Tighter results. Changed the call selection to use a single click.
181
183
  - [24-4-9-4] Check for portaudio instead of crash boom. Removed empty dockwidget. Tested on Plasma 6.
182
184
  - [24-4-9-3] Ugh. It's not a real day unless you forget to test.
@@ -225,7 +227,7 @@ pip install -U not1mm
225
227
  ```bash
226
228
  sudo apt update
227
229
  sudo apt upgrade
228
- sudo apt install -y libportaudio2 pipx
230
+ sudo apt install -y libportaudio2 pipx libxcb-cursor0
229
231
  pipx install not1mm
230
232
  pipx ensurepath
231
233
  ```
@@ -1,9 +1,10 @@
1
1
  not1mm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- not1mm/__main__.py,sha256=Lnwp-STJRcTvjH65oYBTIHcjQ-l0tN0pVsRJylkLJds,123143
2
+ not1mm/__main__.py,sha256=MaYfjKcnvksXTKe65bYRMsmS9uEaRuQv26SspQ02zJM,123596
3
3
  not1mm/bandmap.py,sha256=3kmRYItrBqpjudFb2NnkGNJpDWkwOpGPQbKwHmYnQ-o,34021
4
- not1mm/checkwindow.py,sha256=JiVjJO2RJlFDybeVnBQ8yi-1DnS5aiWs2QTHp_bbn5M,10381
5
- not1mm/fsutils.py,sha256=Li8Tq9K7c_q7onOHOQ7u1dOOFfhIIz5Aj2LKuQtGOO4,1652
4
+ not1mm/checkwindow.py,sha256=9ueFgYLM4RFmroMJBXXn98XWO9ZJ-Dop6MwZUXRNFF0,10577
5
+ not1mm/fsutils.py,sha256=ukHKxKTeNKxKwqRaJjtzRShL4X5Xl0jRBbADyy3Ifp8,1701
6
6
  not1mm/logwindow.py,sha256=UcO8mgs_E7ier2gg_1ESTaRxABEvcpCwKmSibm7hl74,44603
7
+ not1mm/radio.py,sha256=Goz-5TWSWpz5o488HJj1QJ6o5gjE2wP6sWiL1hubk5Y,2414
7
8
  not1mm/vfo.py,sha256=pRRj0XTbeTU9noo3nC1dbg26VYj6gHEw_srUDbyYqC0,12169
8
9
  not1mm/data/JetBrainsMono-Regular.ttf,sha256=UOHctAKY_PzCGh7zy-6f6egnCcSK0wzmF0csBqO9lDY,203952
9
10
  not1mm/data/MASTER.SCP,sha256=1vQRvEZ865brfmmajp-Lj-hgWejVGI992q8o971bUV8,366478
@@ -35,7 +36,7 @@ not1mm/data/radio_green.png,sha256=PXlvRI2x0C8yLVkxRwrZe6tex8k9GtM-1Cj2Vy6KP7o,1
35
36
  not1mm/data/radio_grey.png,sha256=9eOtMHDpQvRYY29D7_vPeacWbwotRXZTMm8EiHE9TW0,1258
36
37
  not1mm/data/radio_red.png,sha256=QvkMk7thd_hCEIyK5xGAG4xVVXivl39nwOfD8USDI20,957
37
38
  not1mm/data/reddot.png,sha256=M33jEMoU8W4rQ4_MVyzzKxDPDte1ypKBch5VnUMNLKE,565
38
- not1mm/data/settings.ui,sha256=7r4aZwxKUHQGm8NLQGLINurGMvT_5VMU9p2dznW25bA,40028
39
+ not1mm/data/settings.ui,sha256=Yvv86OgXS8S3RmM16biDmvS7gp-1FssKoEjmrHy3SSk,40028
39
40
  not1mm/data/ssbmacros.txt,sha256=0Qccj4y0nlK-w5da9a9ti-jILkURtwztoDuL_D0pEJM,470
40
41
  not1mm/data/vfo.ui,sha256=ixer0pVVr8o21j_AmBA3J1OEGd96EXVFhkoNhqIQG10,2054
41
42
  not1mm/data/phonetics/0.wav,sha256=0OpYiR-3MK6fVHE6MB-HeOxSAPiDNMjqvx5JcIZtsQk,42590
@@ -95,7 +96,7 @@ not1mm/lib/edit_contact.py,sha256=Ki9bGPpqyQQBB1cU8VIBDCal3lbXeQ6qxhzklmhE2_w,35
95
96
  not1mm/lib/edit_macro.py,sha256=raKWBwsHInj5EUKmvyLQ6gqc3ZFDlstsD3xqoM4PC8E,517
96
97
  not1mm/lib/edit_opon.py,sha256=j3qJ1aBsQoIOnQ9yiBl3lyeISvKTP0I_rtBYBPAfgeI,359
97
98
  not1mm/lib/edit_station.py,sha256=doL21Hs6jzIE43ohAopdFt_iqnRJZHFcqzcnCS0-iio,1965
98
- not1mm/lib/ft8_watcher.py,sha256=rqvv7v2CXus0U8bekDenHvFVxFpYpzuApW-SA-SdtIA,4220
99
+ not1mm/lib/ft8_watcher.py,sha256=ISfXjs-Mgbz_lE5SThEnFoCe8apNLElgSuECAMCH18I,4080
99
100
  not1mm/lib/ham_utility.py,sha256=pUrysod3wGk4BYOWDAKJxZZTiUNDE4ZzRk8S5ZnllNA,10978
100
101
  not1mm/lib/lookup.py,sha256=F2fl5QkMxaGSxl1XMWnLUub3T9Mt7LhCX4acOlAsks4,13952
101
102
  not1mm/lib/multicast.py,sha256=bnFUNHyy82GmIb3_88EPBVVssj7-HzkJPaH671cK8Qw,3249
@@ -103,9 +104,9 @@ not1mm/lib/n1mm.py,sha256=V1NiNyOHaPNYKe_vRsq44O1R42N8uS5PlfRa5Db4Tv0,5712
103
104
  not1mm/lib/new_contest.py,sha256=IznTDMq7yXHB6zBoGUEC_WDYPCPpsSZW4wwMJi16zK0,816
104
105
  not1mm/lib/plugin_common.py,sha256=AAKBPCXzTWZJb-h08uPNnHVG7bSCg7kwukc211gFivY,8605
105
106
  not1mm/lib/select_contest.py,sha256=WsptLuwkouIHeocJL3oZ6-eUfEnhpwdc-x7eMZ_TIVM,359
106
- not1mm/lib/settings.py,sha256=tlXlJUUZP0IFwIDc9DboM5_1by_tHNtMXvyJ0E7B6RI,8877
107
+ not1mm/lib/settings.py,sha256=i4Za_BZDl9UotB10o8sjIkzRdR0493rMI5VaQltUZHA,9054
107
108
  not1mm/lib/super_check_partial.py,sha256=p5l3u2ZOCBtlWgbvskC50FpuoaIpR07tfC6zTdRWbh4,2334
108
- not1mm/lib/version.py,sha256=TGgIZBlA1udqoabl-Uu2ILq7aYZGkkUWLKSGmHeX38c,48
109
+ not1mm/lib/version.py,sha256=aH3z1Y5ZCxw5yrWiPyG8ZqCLurkMWME0k5P186pnRmA,48
109
110
  not1mm/lib/versiontest.py,sha256=8vDNptuBBunn-1IGkjNaquehqBYUJyjrPSF8Igmd4_Y,1286
110
111
  not1mm/plugins/10_10_fall_cw.py,sha256=fUjfwjuscDjicXIxsO0JHh7xTR9Vu0iPsrOLb896Qak,10873
111
112
  not1mm/plugins/10_10_spring_cw.py,sha256=WNaJP5mBQfaB6SxnFI0Vawt3AKDr94tKVtAK-EVhtUY,10878
@@ -139,9 +140,9 @@ not1mm/plugins/naqp_ssb.py,sha256=IWksulcb2_DxlkeW0h3048t8I-u00G_67KBVKkp-TV4,11
139
140
  not1mm/plugins/phone_weekly_test.py,sha256=gCX0ESUoiQzDp9puwibt9-dRembNsiuEeBdawCVvjHA,12316
140
141
  not1mm/plugins/stew_perry_topband.py,sha256=DIMI3mGMKokXXb9pPLqdhBI6JVnnIs7ZnAL23nFmshE,10588
141
142
  not1mm/plugins/winter_field_day.py,sha256=4rcfRtobwjHO6BNL3WOTHzBmyyeuX79BNGBG8PfjrI8,10238
142
- not1mm-24.4.15.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
143
- not1mm-24.4.15.dist-info/METADATA,sha256=wggnagX-HKqQtkzyr6t0TyX74cpcRmUEKZfCo1IXsHQ,27410
144
- not1mm-24.4.15.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
145
- not1mm-24.4.15.dist-info/entry_points.txt,sha256=pMcZk_0dxFgLkcUkF0Q874ojpwOmF3OL6EKw9LgvocM,47
146
- not1mm-24.4.15.dist-info/top_level.txt,sha256=0YmTxEcDzQlzXub-lXASvoLpg_mt1c2thb5cVkDf5J4,7
147
- not1mm-24.4.15.dist-info/RECORD,,
143
+ not1mm-24.4.24.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
144
+ not1mm-24.4.24.dist-info/METADATA,sha256=CLe_G-OcQDrhUASnzk0xmU4A5aUeZLQ1KdCJaoa9rz0,27677
145
+ not1mm-24.4.24.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
146
+ not1mm-24.4.24.dist-info/entry_points.txt,sha256=pMcZk_0dxFgLkcUkF0Q874ojpwOmF3OL6EKw9LgvocM,47
147
+ not1mm-24.4.24.dist-info/top_level.txt,sha256=0YmTxEcDzQlzXub-lXASvoLpg_mt1c2thb5cVkDf5J4,7
148
+ not1mm-24.4.24.dist-info/RECORD,,