not1mm 24.3.16__py3-none-any.whl → 24.3.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 +288 -124
- not1mm/bandmap.py +207 -191
- not1mm/checkwindow.py +62 -109
- not1mm/data/MASTER.SCP +1077 -749
- not1mm/data/bandmap.ui +4 -4
- not1mm/data/checkwindow.ui +9 -16
- not1mm/data/cty.json +1 -1
- not1mm/data/logwindow.ui +16 -11
- not1mm/data/main.ui +16 -6
- not1mm/data/vfo.ui +64 -52
- not1mm/fsutils.py +63 -0
- not1mm/lib/about.py +4 -2
- not1mm/lib/cat_interface.py +1 -1
- not1mm/lib/cwinterface.py +1 -1
- not1mm/lib/database.py +4 -4
- not1mm/lib/edit_contact.py +2 -2
- not1mm/lib/edit_macro.py +2 -3
- not1mm/lib/edit_opon.py +2 -2
- not1mm/lib/edit_station.py +3 -3
- not1mm/lib/ham_utility.py +1 -1
- not1mm/lib/lookup.py +1 -1
- not1mm/lib/multicast.py +9 -4
- not1mm/lib/n1mm.py +1 -1
- not1mm/lib/new_contest.py +2 -2
- not1mm/lib/select_contest.py +2 -2
- not1mm/lib/settings.py +3 -4
- not1mm/lib/super_check_partial.py +8 -5
- not1mm/lib/version.py +1 -1
- not1mm/logwindow.py +62 -105
- 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 +1 -1
- not1mm/plugins/arrl_dx_cw.py +1 -1
- not1mm/plugins/arrl_dx_ssb.py +1 -1
- not1mm/plugins/arrl_field_day.py +1 -1
- not1mm/plugins/arrl_ss_cw.py +1 -1
- not1mm/plugins/arrl_ss_phone.py +1 -1
- not1mm/plugins/arrl_vhf_jan.py +1 -1
- not1mm/plugins/arrl_vhf_jun.py +1 -1
- not1mm/plugins/arrl_vhf_sep.py +1 -1
- not1mm/plugins/canada_day.py +1 -1
- not1mm/plugins/cq_160_cw.py +1 -1
- not1mm/plugins/cq_160_ssb.py +1 -1
- 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 +1 -1
- not1mm/plugins/general_logging.py +1 -1
- not1mm/plugins/iaru_hf.py +1 -1
- not1mm/plugins/jidx_cw.py +1 -1
- not1mm/plugins/jidx_ph.py +1 -1
- not1mm/plugins/naqp_cw.py +1 -1
- not1mm/plugins/naqp_ssb.py +1 -1
- not1mm/plugins/phone_weekly_test.py +1 -1
- not1mm/plugins/stew_perry_topband.py +1 -1
- not1mm/plugins/winter_field_day.py +1 -1
- not1mm/vfo.py +78 -98
- {not1mm-24.3.16.dist-info → not1mm-24.3.24.dist-info}/METADATA +67 -55
- {not1mm-24.3.16.dist-info → not1mm-24.3.24.dist-info}/RECORD +68 -66
- testing/detectdark.py +35 -0
- testing/test.py +13 -11
- {not1mm-24.3.16.dist-info → not1mm-24.3.24.dist-info}/LICENSE +0 -0
- {not1mm-24.3.16.dist-info → not1mm-24.3.24.dist-info}/WHEEL +0 -0
- {not1mm-24.3.16.dist-info → not1mm-24.3.24.dist-info}/entry_points.txt +0 -0
- {not1mm-24.3.16.dist-info → not1mm-24.3.24.dist-info}/top_level.txt +0 -0
not1mm/vfo.py
CHANGED
@@ -9,58 +9,35 @@ VFO Window
|
|
9
9
|
# usb-Raspberry_Pi_Pico_W_E6614C311B331139-if00
|
10
10
|
|
11
11
|
import logging
|
12
|
-
|
13
12
|
import os
|
14
|
-
|
15
13
|
import platform
|
16
|
-
import queue
|
17
|
-
import sys
|
18
14
|
from json import loads, JSONDecodeError
|
19
|
-
from pathlib import Path
|
20
15
|
|
21
16
|
import serial
|
22
|
-
from PyQt5 import QtCore,
|
23
|
-
from PyQt5.QtCore import QTimer
|
24
|
-
from PyQt5.QtWidgets import
|
17
|
+
from PyQt5 import QtCore, QtGui, QtWidgets, uic
|
18
|
+
from PyQt5.QtCore import Qt, QTimer
|
19
|
+
from PyQt5.QtWidgets import QWidget
|
25
20
|
|
21
|
+
import not1mm.fsutils as fsutils
|
26
22
|
from not1mm.lib.cat_interface import CAT
|
27
23
|
from not1mm.lib.multicast import Multicast
|
28
24
|
|
29
|
-
|
30
|
-
|
31
|
-
if __loader__:
|
32
|
-
WORKING_PATH = os.path.dirname(__loader__.get_filename())
|
33
|
-
else:
|
34
|
-
WORKING_PATH = os.path.dirname(os.path.realpath(__file__))
|
25
|
+
logger = logging.getLogger(__name__)
|
35
26
|
|
36
|
-
if "XDG_DATA_HOME" in os.environ:
|
37
|
-
DATA_PATH = os.environ.get("XDG_DATA_HOME")
|
38
|
-
else:
|
39
|
-
DATA_PATH = str(Path.home() / ".local" / "share")
|
40
|
-
DATA_PATH += "/not1mm"
|
41
27
|
|
42
|
-
|
43
|
-
|
44
|
-
else:
|
45
|
-
CONFIG_PATH = str(Path.home() / ".config")
|
46
|
-
CONFIG_PATH += "/not1mm"
|
47
|
-
|
48
|
-
|
49
|
-
class MainWindow(QMainWindow):
|
50
|
-
"""
|
51
|
-
The main window
|
52
|
-
"""
|
28
|
+
class VfoWindow(QWidget):
|
29
|
+
"""The VFO window."""
|
53
30
|
|
54
31
|
pref = {}
|
55
32
|
old_vfo = ""
|
56
33
|
old_pico = ""
|
57
34
|
message_shown = False
|
58
35
|
multicast_interface = None
|
36
|
+
current_palette = None
|
59
37
|
|
60
38
|
def __init__(self, *args, **kwargs):
|
61
39
|
super().__init__(*args, **kwargs)
|
62
|
-
|
63
|
-
uic.loadUi(data_path, self)
|
40
|
+
uic.loadUi(fsutils.APP_DATA_PATH / "vfo.ui", self)
|
64
41
|
self.rig_control = None
|
65
42
|
self.timer = QTimer()
|
66
43
|
self.timer.timeout.connect(self.getwaiting)
|
@@ -69,7 +46,7 @@ class MainWindow(QMainWindow):
|
|
69
46
|
self.lcdNumber.display(0)
|
70
47
|
self.pico = None
|
71
48
|
self._udpwatch = None
|
72
|
-
|
49
|
+
|
73
50
|
self.multicast_interface = Multicast(
|
74
51
|
self.pref.get("multicast_group", "239.1.1.1"),
|
75
52
|
self.pref.get("multicast_port", 2239),
|
@@ -77,9 +54,45 @@ class MainWindow(QMainWindow):
|
|
77
54
|
)
|
78
55
|
self.multicast_interface.ready_read_connect(self.watch_udp)
|
79
56
|
|
80
|
-
|
81
|
-
|
82
|
-
|
57
|
+
self.setup_serial()
|
58
|
+
# app.processEvents()
|
59
|
+
self.poll_rig_timer = QtCore.QTimer()
|
60
|
+
self.poll_rig_timer.timeout.connect(self.poll_radio)
|
61
|
+
self.poll_rig_timer.start(500)
|
62
|
+
|
63
|
+
def setDarkMode(self, dark: bool):
|
64
|
+
"""testing"""
|
65
|
+
|
66
|
+
if dark:
|
67
|
+
darkPalette = QtGui.QPalette()
|
68
|
+
darkColor = QtGui.QColor(45, 45, 45)
|
69
|
+
disabledColor = QtGui.QColor(127, 127, 127)
|
70
|
+
darkPalette.setColor(QtGui.QPalette.Window, darkColor)
|
71
|
+
darkPalette.setColor(QtGui.QPalette.WindowText, Qt.white)
|
72
|
+
darkPalette.setColor(QtGui.QPalette.Base, QtGui.QColor(18, 18, 18))
|
73
|
+
darkPalette.setColor(QtGui.QPalette.AlternateBase, darkColor)
|
74
|
+
darkPalette.setColor(QtGui.QPalette.Text, Qt.white)
|
75
|
+
darkPalette.setColor(
|
76
|
+
QtGui.QPalette.Disabled, QtGui.QPalette.Text, disabledColor
|
77
|
+
)
|
78
|
+
darkPalette.setColor(QtGui.QPalette.Button, darkColor)
|
79
|
+
darkPalette.setColor(QtGui.QPalette.ButtonText, Qt.white)
|
80
|
+
darkPalette.setColor(
|
81
|
+
QtGui.QPalette.Disabled, QtGui.QPalette.ButtonText, disabledColor
|
82
|
+
)
|
83
|
+
darkPalette.setColor(QtGui.QPalette.BrightText, Qt.red)
|
84
|
+
darkPalette.setColor(QtGui.QPalette.Link, QtGui.QColor(42, 130, 218))
|
85
|
+
darkPalette.setColor(QtGui.QPalette.Highlight, QtGui.QColor(42, 130, 218))
|
86
|
+
darkPalette.setColor(QtGui.QPalette.HighlightedText, Qt.black)
|
87
|
+
darkPalette.setColor(
|
88
|
+
QtGui.QPalette.Disabled, QtGui.QPalette.HighlightedText, disabledColor
|
89
|
+
)
|
90
|
+
self.current_palette = darkPalette
|
91
|
+
self.setPalette(darkPalette)
|
92
|
+
else:
|
93
|
+
palette = self.style().standardPalette()
|
94
|
+
self.current_palette = palette
|
95
|
+
self.setPalette(palette)
|
83
96
|
|
84
97
|
def load_pref(self) -> None:
|
85
98
|
"""
|
@@ -87,9 +100,9 @@ class MainWindow(QMainWindow):
|
|
87
100
|
Get CAT interface.
|
88
101
|
"""
|
89
102
|
try:
|
90
|
-
if os.path.exists(
|
103
|
+
if os.path.exists(fsutils.CONFIG_FILE):
|
91
104
|
with open(
|
92
|
-
|
105
|
+
fsutils.CONFIG_FILE, "rt", encoding="utf-8"
|
93
106
|
) as file_descriptor:
|
94
107
|
self.pref = loads(file_descriptor.read())
|
95
108
|
logger.info("%s", self.pref)
|
@@ -119,6 +132,7 @@ class MainWindow(QMainWindow):
|
|
119
132
|
int(self.pref.get("CAT_port", 4532)),
|
120
133
|
)
|
121
134
|
self.timer.start(100)
|
135
|
+
self.setDarkMode(self.pref.get("darkmode", False))
|
122
136
|
|
123
137
|
def discover_device(self) -> str:
|
124
138
|
"""
|
@@ -131,7 +145,7 @@ class MainWindow(QMainWindow):
|
|
131
145
|
|
132
146
|
devices = None
|
133
147
|
data = None
|
134
|
-
app.processEvents()
|
148
|
+
# app.processEvents()
|
135
149
|
try:
|
136
150
|
devices = os.listdir("/dev/serial/by-id")
|
137
151
|
except FileNotFoundError:
|
@@ -154,29 +168,28 @@ class MainWindow(QMainWindow):
|
|
154
168
|
Setup the device returned by discover_device()
|
155
169
|
Or display message saying we didn't find one.
|
156
170
|
"""
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
except OSError:
|
166
|
-
if self.message_shown is False:
|
167
|
-
self.message_shown = True
|
168
|
-
self.show_message_box(
|
169
|
-
"Unable to locate or open the VFO knob serial device."
|
170
|
-
)
|
171
|
-
self.lcdNumber.setStyleSheet("QLCDNumber { color: red; }")
|
172
|
-
else:
|
171
|
+
|
172
|
+
device = self.discover_device()
|
173
|
+
if device:
|
174
|
+
try:
|
175
|
+
self.pico = serial.Serial("/dev/serial/by-id/" + device, 115200)
|
176
|
+
self.pico.timeout = 100
|
177
|
+
self.lcdNumber.setStyleSheet("QLCDNumber { color: white; }")
|
178
|
+
except OSError:
|
173
179
|
if self.message_shown is False:
|
174
180
|
self.message_shown = True
|
175
181
|
self.show_message_box(
|
176
182
|
"Unable to locate or open the VFO knob serial device."
|
177
183
|
)
|
178
184
|
self.lcdNumber.setStyleSheet("QLCDNumber { color: red; }")
|
179
|
-
|
185
|
+
else:
|
186
|
+
if self.message_shown is False:
|
187
|
+
self.message_shown = True
|
188
|
+
self.show_message_box(
|
189
|
+
"Unable to locate or open the VFO knob serial device."
|
190
|
+
)
|
191
|
+
self.lcdNumber.setStyleSheet("QLCDNumber { color: red; }")
|
192
|
+
# app.processEvents()
|
180
193
|
|
181
194
|
def watch_udp(self) -> None:
|
182
195
|
"""
|
@@ -200,8 +213,7 @@ class MainWindow(QMainWindow):
|
|
200
213
|
if json_data.get("station", "") != platform.node():
|
201
214
|
continue
|
202
215
|
logger.debug(f"{json_data=}")
|
203
|
-
|
204
|
-
self.quit_app()
|
216
|
+
|
205
217
|
if json_data.get("cmd", "") == "TUNE":
|
206
218
|
# b'{"cmd": "TUNE", "freq": 7.0235, "spot": "MM0DGI"}'
|
207
219
|
vfo = json_data.get("freq")
|
@@ -214,6 +226,9 @@ class MainWindow(QMainWindow):
|
|
214
226
|
logger.critical("Unable to write to serial device.")
|
215
227
|
except AttributeError:
|
216
228
|
logger.critical("Unable to write to serial device.")
|
229
|
+
continue
|
230
|
+
if json_data.get("cmd", "") == "DARKMODE":
|
231
|
+
self.setDarkMode(json_data.get("state", False))
|
217
232
|
|
218
233
|
def showNumber(self, the_number) -> None:
|
219
234
|
"""Display vfo value with dots"""
|
@@ -221,7 +236,7 @@ class MainWindow(QMainWindow):
|
|
221
236
|
if len(dvfo) > 6:
|
222
237
|
dnum = f"{dvfo[:len(dvfo)-6]}.{dvfo[-6:-3]}.{dvfo[-3:]}"
|
223
238
|
self.lcdNumber.display(dnum)
|
224
|
-
app.processEvents()
|
239
|
+
# app.processEvents()
|
225
240
|
|
226
241
|
def poll_radio(self) -> None:
|
227
242
|
"""
|
@@ -244,7 +259,7 @@ class MainWindow(QMainWindow):
|
|
244
259
|
logger.debug(f"{vfo}")
|
245
260
|
self.showNumber(vfo)
|
246
261
|
# self.lcdNumber.display(dnum)
|
247
|
-
app.processEvents()
|
262
|
+
# app.processEvents()
|
248
263
|
cmd = f"F {vfo}\r"
|
249
264
|
try:
|
250
265
|
if self.pico:
|
@@ -271,56 +286,21 @@ class MainWindow(QMainWindow):
|
|
271
286
|
self.rig_control.set_vfo(result)
|
272
287
|
self.showNumber(result)
|
273
288
|
# self.lcdNumber.display(result)
|
274
|
-
app.processEvents()
|
289
|
+
# app.processEvents()
|
275
290
|
except OSError:
|
276
291
|
logger.critical("Unable to write to serial device.")
|
277
292
|
except AttributeError:
|
278
293
|
logger.critical("Unable to write to serial device.")
|
279
|
-
app.processEvents()
|
294
|
+
# app.processEvents()
|
280
295
|
|
281
296
|
def show_message_box(self, message: str) -> None:
|
282
297
|
"""
|
283
298
|
Display an alert box with the supplied message.
|
284
299
|
"""
|
285
300
|
message_box = QtWidgets.QMessageBox()
|
301
|
+
message_box.setPalette(self.current_palette)
|
286
302
|
message_box.setIcon(QtWidgets.QMessageBox.Information)
|
287
303
|
message_box.setText(message)
|
288
304
|
message_box.setWindowTitle("Information")
|
289
305
|
message_box.setStandardButtons(QtWidgets.QMessageBox.Ok)
|
290
306
|
_ = message_box.exec_()
|
291
|
-
|
292
|
-
|
293
|
-
def main():
|
294
|
-
"""main entry"""
|
295
|
-
window.show()
|
296
|
-
window.setup_serial()
|
297
|
-
app.processEvents()
|
298
|
-
timer = QtCore.QTimer()
|
299
|
-
timer.timeout.connect(window.poll_radio)
|
300
|
-
timer.start(250)
|
301
|
-
sys.exit(app.exec())
|
302
|
-
|
303
|
-
|
304
|
-
logger = logging.getLogger("__main__")
|
305
|
-
handler = logging.StreamHandler()
|
306
|
-
formatter = logging.Formatter(
|
307
|
-
datefmt="%H:%M:%S",
|
308
|
-
fmt="[%(asctime)s] %(levelname)s %(module)s - %(funcName)s Line %(lineno)d:\n%(message)s",
|
309
|
-
)
|
310
|
-
handler.setFormatter(formatter)
|
311
|
-
logger.addHandler(handler)
|
312
|
-
|
313
|
-
if Path("./debug").exists():
|
314
|
-
logger.setLevel(logging.DEBUG)
|
315
|
-
logger.debug("debugging on")
|
316
|
-
else:
|
317
|
-
logger.setLevel(logging.WARNING)
|
318
|
-
logger.warning("debugging off")
|
319
|
-
|
320
|
-
app = QApplication(sys.argv)
|
321
|
-
app.setStyle("Adwaita-Dark")
|
322
|
-
window = MainWindow()
|
323
|
-
|
324
|
-
|
325
|
-
if __name__ == "__main__":
|
326
|
-
main()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: not1mm
|
3
|
-
Version: 24.3.
|
3
|
+
Version: 24.3.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
|
@@ -27,6 +27,7 @@ Requires-Dist: soundfile
|
|
27
27
|
Requires-Dist: numpy
|
28
28
|
Requires-Dist: notctyparser >=23.6.21
|
29
29
|
Requires-Dist: rapidfuzz
|
30
|
+
Requires-Dist: appdata
|
30
31
|
|
31
32
|
# Not1MM
|
32
33
|
|
@@ -47,19 +48,16 @@ The worlds #1 unfinished contest logger <sup>*According to my daughter Corinna.<
|
|
47
48
|
- [Our Code Contributors ✨](#our-code-contributors-)
|
48
49
|
- [List of should be working contests](#list-of-should-be-working-contests)
|
49
50
|
- [Recent Changes](#recent-changes)
|
50
|
-
- [
|
51
|
-
- [Python and
|
52
|
-
- [
|
53
|
-
|
54
|
-
|
55
|
-
|
51
|
+
- [Installation](#installation)
|
52
|
+
- [Python, PyPI, pip and pipx](#python-pypi-pip-and-pipx)
|
53
|
+
- [Bootstrapping pipx](#bootstrapping-pipx)
|
54
|
+
- [Installing with pipx](#installing-with-pipx)
|
55
|
+
- [Installing portaudio](#installing-portaudio)
|
56
|
+
- [After install](#after-install)
|
56
57
|
- [You may or may not get a warning message like](#you-may-or-may-not-get-a-warning-message-like)
|
57
58
|
- [Or this fan favorite](#or-this-fan-favorite)
|
58
|
-
- [Updating with pip/pipx](#updating-with-pippipx)
|
59
|
-
- [Other Libraries](#other-libraries)
|
60
|
-
- [Dark mode on Ubuntu](#dark-mode-on-ubuntu)
|
61
59
|
- [Wayland Compositor](#wayland-compositor)
|
62
|
-
|
60
|
+
- [Running from source](#running-from-source)
|
63
61
|
- [Various data file locations](#various-data-file-locations)
|
64
62
|
- [Data](#data)
|
65
63
|
- [Config](#config)
|
@@ -70,13 +68,14 @@ The worlds #1 unfinished contest logger <sup>*According to my daughter Corinna.<
|
|
70
68
|
- [Revisiting an old friend](#revisiting-an-old-friend)
|
71
69
|
- [Station Settings dialog (REQUIRED)](#station-settings-dialog-required)
|
72
70
|
- [Changing station information](#changing-station-information)
|
73
|
-
- [
|
74
|
-
|
75
|
-
|
71
|
+
- [Selecting a contest (REQUIRED)](#selecting-a-contest-required)
|
72
|
+
- [Selecting a new contest](#selecting-a-new-contest)
|
73
|
+
- [Selecting an existing contest as the current contest](#selecting-an-existing-contest-as-the-current-contest)
|
74
|
+
- [Editing existing contest parameters](#editing-existing-contest-parameters)
|
76
75
|
- [Configuration Settings](#configuration-settings)
|
77
76
|
- [Lookup](#lookup)
|
78
77
|
- [Soundcard](#soundcard)
|
79
|
-
- [CAT](#cat)
|
78
|
+
- [CAT Control](#cat-control)
|
80
79
|
- [CW Keyer interface](#cw-keyer-interface)
|
81
80
|
- [Cluster](#cluster)
|
82
81
|
- [N1MM Packets](#n1mm-packets)
|
@@ -89,7 +88,7 @@ The worlds #1 unfinished contest logger <sup>*According to my daughter Corinna.<
|
|
89
88
|
- [Other uses for the call field](#other-uses-for-the-call-field)
|
90
89
|
- [Windows](#windows)
|
91
90
|
- [The Main Window](#the-main-window)
|
92
|
-
|
91
|
+
- [Keyboard commands](#keyboard-commands)
|
93
92
|
- [Log Display](#log-display)
|
94
93
|
- [Editing a contact](#editing-a-contact)
|
95
94
|
- [Recalulate Mults](#recalulate-mults)
|
@@ -168,6 +167,10 @@ I wish to thank those who've contributed to the project.
|
|
168
167
|
|
169
168
|
## Recent Changes
|
170
169
|
|
170
|
+
- [24-3-24] Reworked fsutil.py to correct directory paths for Linux.
|
171
|
+
- [24-3-23] Yanked version 24-3-21, too many bugs for existing userbase.
|
172
|
+
- [24-3-21] Merged PR from @kyleboyle for docking windows. MacOS and Windows support.
|
173
|
+
- [24-3-19] Removed some useless bloat causing slow interface on FreeBSD 13/14 and maybe others.
|
171
174
|
- [24-3-16] Add Save/Fail confirmation dialogs when saving ADIF of Cabrillo files.
|
172
175
|
- [24-3-15] Change 'CWR' to 'CW' in the ADIF output.
|
173
176
|
- [24-3-13] Added CQ 160 CW and SSB
|
@@ -178,43 +181,64 @@ I wish to thank those who've contributed to the project.
|
|
178
181
|
|
179
182
|
See [CHANGELOG.md](CHANGELOG.md) for prior changes.
|
180
183
|
|
181
|
-
##
|
184
|
+
## Installation
|
182
185
|
|
183
|
-
### Python and
|
186
|
+
### Python, PyPI, pip and pipx
|
184
187
|
|
185
|
-
This software is a Python package hosted on
|
188
|
+
This software is a Python package hosted on PyPI, and installable with the pip or pipx command. If this is your first exposure to Python packaging you can get all the details from:
|
186
189
|
|
187
|
-
|
190
|
+
- [The PyPA](https://packaging.python.org/en/latest/tutorials/installing-packages/)
|
191
|
+
- [Install packages in a virtual environment using pip and venv](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/)
|
192
|
+
- [Installing stand alone command line tools](https://packaging.python.org/en/latest/guides/installing-stand-alone-command-line-tools/)
|
188
193
|
|
189
|
-
|
194
|
+
In short, You should install stuff into a Python virtual environment. Newer Linux distros will make you do this unless you include a command line argument akin to '--break-my-system' when using pip. I'm not telling you to use pipx. But... **Use pipx**.
|
190
195
|
|
191
|
-
|
196
|
+
### Bootstrapping pipx
|
197
|
+
|
198
|
+
Assuming you have only Python installed, your path to pipx is:
|
192
199
|
|
193
200
|
```bash
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
pip
|
201
|
+
# First get pip installed. Either with apt or dnf, or the ensurepip command.
|
202
|
+
python3 -m ensurepip
|
203
|
+
|
204
|
+
# Update the pip that was just installed.
|
205
|
+
python3 -m pip install --upgrade pip
|
206
|
+
|
207
|
+
# Install pipx
|
208
|
+
python3 -m pip install --user pipx
|
209
|
+
python3 -m pipx ensurepath
|
198
210
|
```
|
199
211
|
|
200
|
-
|
212
|
+
### Installing with pipx
|
213
|
+
|
214
|
+
Then installing not1mm is as simple as:
|
201
215
|
|
202
216
|
```bash
|
203
|
-
|
204
|
-
sudo apt upgrade
|
205
|
-
sudo apt install -y libportaudio2 adwaita-qt pipx
|
217
|
+
# Install not1mm
|
206
218
|
pipx install not1mm
|
207
|
-
pipx ensurepath
|
208
219
|
```
|
209
220
|
|
210
|
-
|
221
|
+
If you need to later update not1mm, you can do so with:
|
222
|
+
|
223
|
+
```bash
|
224
|
+
# Update not1mm
|
225
|
+
pipx upgrade not1mm
|
226
|
+
```
|
227
|
+
|
228
|
+
### Installing portaudio
|
229
|
+
|
230
|
+
not1mm uses portaudio to play audio. You can install it with:
|
211
231
|
|
212
232
|
```bash
|
213
|
-
|
233
|
+
# Ubuntu
|
234
|
+
sudo apt install -y libportaudio2
|
235
|
+
|
236
|
+
# Fedora
|
214
237
|
sudo dnf install python3-pip portaudio
|
215
|
-
pip install not1mm
|
216
238
|
```
|
217
239
|
|
240
|
+
## After install
|
241
|
+
|
218
242
|
You can now open a new terminal and type `not1mm`. On it's first run, it may or may not install a lovely non AI generated
|
219
243
|
icon, which you can later click on to launch the application.
|
220
244
|
|
@@ -241,27 +265,13 @@ To avoid this you can export an environment variable and launch the app like thi
|
|
241
265
|
|
242
266
|
For a more permanent solution you can place the line `export QT_QPA_PLATFORM=wayland` in your home directories .bashrc file. Then after logging out and back in you should be able to launch it normally.
|
243
267
|
|
244
|
-
### Updating with pip/pipx
|
245
|
-
|
246
|
-
I've been posting updates just about everyday. Sometimes multiple times a day. It's early days, so there is much to do. You can check for and install updates with `pip install -U not1mm` or if installed with pipx `pipx upgrade not1mm`.
|
247
|
-
|
248
|
-
## Other Libraries
|
249
|
-
|
250
|
-
The audio library used, uses pipewire/portaudio. You may need to install portaudio. Ubuntu: `sudo apt install libportaudio2`
|
251
|
-
|
252
|
-
### Dark mode on Ubuntu
|
253
|
-
|
254
|
-
I believe I figured out dark mode in Ubuntu and have it working on my shack PC that runs Ubuntu 22.04. The secret sauce seems to be installing adwaita-qt with apt, and setting an environment variable `QT_STYLE_OVERRIDE` to `Adwaita-Dark`. I set the environment variable in the start of the program if running on a Gnome platform. So you don't need to do that part.
|
255
|
-
|
256
|
-
Or see this discussion [darkmode](https://github.com/mbridak/not1mm/discussions/60).
|
257
|
-
|
258
268
|
## Wayland Compositor
|
259
269
|
|
260
270
|
One side effect of Wayland is that we are not able to request for a window to regain or retain focus. So if you were to click on a spot in the bandmap window to tune to that spot, you would have to then click on the main window to continue entering contest data. I'm aware of this, but I can not change it.
|
261
271
|
|
262
|
-
|
272
|
+
### Running from source
|
263
273
|
|
264
|
-
Since this is packaged for
|
274
|
+
Since this is packaged for PyPI, if you want to work on your own source branch, after cloning from github you would:
|
265
275
|
|
266
276
|
```bash
|
267
277
|
pip install --upgrade pip
|
@@ -330,19 +340,21 @@ You can fill. You can fill. Everyone look at your keys.
|
|
330
340
|
|
331
341
|
Station information can be changed any time by going to `File` > `Station Settings` and editing the information.
|
332
342
|
|
333
|
-
##
|
343
|
+
## Selecting a contest (REQUIRED)
|
344
|
+
|
345
|
+
### Selecting a new contest
|
334
346
|
|
335
347
|
Select `File` > `New Contest`
|
336
348
|
|
337
349
|

|
338
350
|
|
339
|
-
|
351
|
+
### Selecting an existing contest as the current contest
|
340
352
|
|
341
353
|
Select `File` > `Open Contest`
|
342
354
|
|
343
355
|

|
344
356
|
|
345
|
-
|
357
|
+
### Editing existing contest parameters
|
346
358
|
|
347
359
|
You can edit the parameters of a previously defined contest by selecting it as the current contest. Then select `File` > `Edit Current Contest`. Click `OK` to save the new values and reload the contest. `Cancel` to keep the existing parameters.
|
348
360
|
|
@@ -362,7 +374,7 @@ For callsign lookup, Two services are supported. QRZ and HamQTH. They require a
|
|
362
374
|
|
363
375
|
Choose the sound output device for the voice keyer.
|
364
376
|
|
365
|
-
### CAT
|
377
|
+
### CAT Control
|
366
378
|
|
367
379
|
Under the `CAT` TAB, you can choose either `rigctld` normally with an IP of `127.0.0.1` and a port of `4532`. Or `flrig`, IP normally of `127.0.0.1` and a port of `12345`. `None` is always an option, but is it really? There's an onscreen icon for CAT status. Green good, Red bad, Grey neither.
|
368
380
|
|
@@ -445,7 +457,7 @@ After this, a request is made to QRZ for the gridsquare of the callsign. If ther
|
|
445
457
|
|
446
458
|

|
447
459
|
|
448
|
-
|
460
|
+
### Keyboard commands
|
449
461
|
|
450
462
|
| Key | Result |
|
451
463
|
| -------------- | --- |
|