not1mm 24.4.26__py3-none-any.whl → 24.5.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.
- not1mm/__main__.py +55 -150
- not1mm/bandmap.py +28 -81
- not1mm/checkwindow.py +23 -35
- not1mm/data/configuration.ui +5 -5
- not1mm/lib/cat_interface.py +28 -0
- not1mm/lib/cwinterface.py +18 -6
- not1mm/lib/settings.py +6 -1
- not1mm/lib/version.py +1 -1
- not1mm/logwindow.py +37 -50
- not1mm/radio.py +9 -0
- not1mm/vfo.py +26 -38
- not1mm/voice_keying.py +100 -0
- {not1mm-24.4.26.dist-info → not1mm-24.5.1.dist-info}/METADATA +57 -50
- {not1mm-24.4.26.dist-info → not1mm-24.5.1.dist-info}/RECORD +18 -17
- {not1mm-24.4.26.dist-info → not1mm-24.5.1.dist-info}/LICENSE +0 -0
- {not1mm-24.4.26.dist-info → not1mm-24.5.1.dist-info}/WHEEL +0 -0
- {not1mm-24.4.26.dist-info → not1mm-24.5.1.dist-info}/entry_points.txt +0 -0
- {not1mm-24.4.26.dist-info → not1mm-24.5.1.dist-info}/top_level.txt +0 -0
not1mm/lib/cwinterface.py
CHANGED
@@ -15,10 +15,17 @@ logger = logging.getLogger("cwinterface")
|
|
15
15
|
|
16
16
|
|
17
17
|
class CW:
|
18
|
-
"""
|
18
|
+
"""
|
19
|
+
|
20
|
+
An interface to cwdaemon and PyWinkeyerSerial
|
21
|
+
|
22
|
+
servertype: int 1=cwdaemon, 2=pywinkeyer, 3=rigctld
|
23
|
+
|
24
|
+
"""
|
19
25
|
|
20
26
|
def __init__(self, servertype: int, host: str, port: int) -> None:
|
21
27
|
self.servertype = servertype
|
28
|
+
self.cat = None
|
22
29
|
self.host = host
|
23
30
|
self.port = port
|
24
31
|
self.speed = 20
|
@@ -42,35 +49,40 @@ class CW:
|
|
42
49
|
|
43
50
|
def sendcw(self, texttosend):
|
44
51
|
"""sends cw to k1el"""
|
45
|
-
logger.
|
52
|
+
logger.debug(f"{texttosend=} {self.servertype=}")
|
46
53
|
if self.servertype == 2:
|
47
54
|
self._sendcw_xmlrpc(texttosend)
|
48
55
|
if self.servertype == 1:
|
49
56
|
self._sendcw_udp(texttosend)
|
57
|
+
if self.servertype == 3 and self.cw is not None:
|
58
|
+
self._sendcwcat(texttosend)
|
50
59
|
|
51
60
|
def _sendcw_xmlrpc(self, texttosend):
|
52
61
|
"""sends cw to xmlrpc"""
|
53
|
-
logger.
|
62
|
+
logger.debug("xmlrpc: %s", texttosend)
|
54
63
|
with ServerProxy(f"http://{self.host}:{self.port}") as proxy:
|
55
64
|
try:
|
56
65
|
proxy.k1elsendstring(texttosend)
|
57
66
|
except Error as exception:
|
58
|
-
logger.
|
67
|
+
logger.debug(
|
59
68
|
"http://%s:%s, xmlrpc error: %s", self.host, self.port, exception
|
60
69
|
)
|
61
70
|
except ConnectionRefusedError:
|
62
|
-
logger.
|
71
|
+
logger.debug(
|
63
72
|
"http://%s:%s, xmlrpc Connection Refused", self.host, self.port
|
64
73
|
)
|
65
74
|
|
66
75
|
def _sendcw_udp(self, texttosend):
|
67
76
|
"""send cw to udp port"""
|
68
|
-
logger.
|
77
|
+
logger.debug("UDP: %s", texttosend)
|
69
78
|
server_address_port = (self.host, self.port)
|
70
79
|
# bufferSize = 1024
|
71
80
|
udp_client_socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
|
72
81
|
udp_client_socket.sendto(bytes(texttosend, "utf-8"), server_address_port)
|
73
82
|
|
83
|
+
def _sendcwcat(self, texttosend):
|
84
|
+
"""..."""
|
85
|
+
|
74
86
|
def set_winkeyer_speed(self, speed):
|
75
87
|
"""doc"""
|
76
88
|
with ServerProxy(f"http://{self.host}:{self.port}") as proxy:
|
not1mm/lib/settings.py
CHANGED
@@ -58,6 +58,9 @@ class Settings(QtWidgets.QDialog):
|
|
58
58
|
self.usepywinkeyer_radioButton.setChecked(
|
59
59
|
bool(self.preference.get("cwtype") == 2)
|
60
60
|
)
|
61
|
+
self.usecwviacat_radioButton.setChecked(
|
62
|
+
bool(self.preference.get("cwtype") == 3)
|
63
|
+
)
|
61
64
|
self.connect_to_server.setChecked(bool(self.preference.get("useserver")))
|
62
65
|
self.multicast_group.setText(str(self.preference.get("multicast_group", "")))
|
63
66
|
self.multicast_port.setText(str(self.preference.get("multicast_port", "")))
|
@@ -131,8 +134,10 @@ class Settings(QtWidgets.QDialog):
|
|
131
134
|
self.preference["cwtype"] = 0
|
132
135
|
if self.usecwdaemon_radioButton.isChecked():
|
133
136
|
self.preference["cwtype"] = 1
|
134
|
-
|
137
|
+
elif self.usepywinkeyer_radioButton.isChecked():
|
135
138
|
self.preference["cwtype"] = 2
|
139
|
+
elif self.usecwviacat_radioButton.isChecked():
|
140
|
+
self.preference["cwtype"] = 3
|
136
141
|
self.preference["useserver"] = self.connect_to_server.isChecked()
|
137
142
|
self.preference["multicast_group"] = self.multicast_group.text()
|
138
143
|
self.preference["multicast_port"] = self.multicast_port.text()
|
not1mm/lib/version.py
CHANGED
not1mm/logwindow.py
CHANGED
@@ -17,6 +17,7 @@ import math
|
|
17
17
|
from PyQt6 import QtCore, QtGui, QtWidgets, uic
|
18
18
|
from PyQt6.QtCore import QItemSelectionModel
|
19
19
|
from PyQt6.QtWidgets import QDockWidget
|
20
|
+
from PyQt6.QtGui import QColorConstants, QPalette, QColor
|
20
21
|
|
21
22
|
import not1mm.fsutils as fsutils
|
22
23
|
from not1mm.lib.database import DataBase
|
@@ -167,58 +168,44 @@ class LogWindow(QDockWidget):
|
|
167
168
|
|
168
169
|
self.multicast_interface.send_as_json(cmd)
|
169
170
|
|
170
|
-
def set_dark_mode(self, dark: bool):
|
171
|
-
"""
|
171
|
+
def set_dark_mode(self, dark: bool) -> None:
|
172
|
+
"""Forces a darkmode palette."""
|
172
173
|
|
173
174
|
if dark:
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
)
|
181
|
-
|
182
|
-
|
183
|
-
)
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
)
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
dark_palette.setColor(
|
209
|
-
QtGui.QPalette.ColorRole.Highlight, QtGui.QColor(42, 130, 218)
|
210
|
-
)
|
211
|
-
dark_palette.setColor(
|
212
|
-
QtGui.QPalette.ColorRole.HighlightedText, QtGui.QColorConstants.Black
|
213
|
-
)
|
214
|
-
dark_palette.setColor(
|
215
|
-
QtGui.QPalette.ColorGroup.Disabled,
|
216
|
-
QtGui.QPalette.ColorRole.HighlightedText,
|
217
|
-
disabled_color,
|
218
|
-
)
|
219
|
-
|
220
|
-
self.setPalette(dark_palette)
|
221
|
-
self.current_palette = dark_palette
|
175
|
+
darkPalette = QPalette()
|
176
|
+
darkColor = QColor(56, 56, 56)
|
177
|
+
disabledColor = QColor(127, 127, 127)
|
178
|
+
darkPalette.setColor(QPalette.ColorRole.Window, darkColor)
|
179
|
+
darkPalette.setColor(QPalette.ColorRole.WindowText, QColorConstants.White)
|
180
|
+
darkPalette.setColor(QPalette.ColorRole.Base, QColor(45, 45, 45))
|
181
|
+
darkPalette.setColor(QPalette.ColorRole.AlternateBase, darkColor)
|
182
|
+
darkPalette.setColor(QPalette.ColorRole.Text, QColorConstants.White)
|
183
|
+
darkPalette.setColor(QPalette.ColorRole.Button, darkColor)
|
184
|
+
darkPalette.setColor(QPalette.ColorRole.ButtonText, QColorConstants.White)
|
185
|
+
darkPalette.setColor(QPalette.ColorRole.BrightText, QColorConstants.Red)
|
186
|
+
darkPalette.setColor(QPalette.ColorRole.Link, QColor(42, 130, 218))
|
187
|
+
darkPalette.setColor(QPalette.ColorRole.Highlight, QColor(42, 130, 218))
|
188
|
+
darkPalette.setColor(
|
189
|
+
QPalette.ColorRole.HighlightedText, QColorConstants.Black
|
190
|
+
)
|
191
|
+
darkPalette.setColor(
|
192
|
+
QPalette.ColorGroup.Disabled,
|
193
|
+
QPalette.ColorRole.ButtonText,
|
194
|
+
disabledColor,
|
195
|
+
)
|
196
|
+
darkPalette.setColor(
|
197
|
+
QPalette.ColorGroup.Disabled,
|
198
|
+
QPalette.ColorRole.HighlightedText,
|
199
|
+
disabledColor,
|
200
|
+
)
|
201
|
+
darkPalette.setColor(
|
202
|
+
QPalette.ColorGroup.Disabled,
|
203
|
+
QPalette.ColorRole.Text,
|
204
|
+
disabledColor,
|
205
|
+
)
|
206
|
+
|
207
|
+
self.setPalette(darkPalette)
|
208
|
+
self.current_palette = darkPalette
|
222
209
|
else:
|
223
210
|
palette = self.style().standardPalette()
|
224
211
|
self.setPalette(palette)
|
not1mm/radio.py
CHANGED
@@ -10,10 +10,13 @@ GPL V3
|
|
10
10
|
# pylint: disable=logging-fstring-interpolation, line-too-long, no-name-in-module
|
11
11
|
|
12
12
|
import datetime
|
13
|
+
import logging
|
13
14
|
|
14
15
|
from PyQt6.QtCore import QObject, pyqtSignal, QThread
|
15
16
|
from not1mm.lib.cat_interface import CAT
|
16
17
|
|
18
|
+
logger = logging.getLogger("cat_interface")
|
19
|
+
|
17
20
|
|
18
21
|
class Radio(QObject):
|
19
22
|
"""Radio class"""
|
@@ -72,6 +75,12 @@ class Radio(QObject):
|
|
72
75
|
)
|
73
76
|
QThread.msleep(100)
|
74
77
|
|
78
|
+
def sendcw(self, texttosend):
|
79
|
+
"""..."""
|
80
|
+
logger.debug(f"Send CW: {texttosend}")
|
81
|
+
if self.cat:
|
82
|
+
self.cat.sendcw(texttosend)
|
83
|
+
|
75
84
|
def set_vfo(self, vfo):
|
76
85
|
if self.cat:
|
77
86
|
self.cat.set_vfo(vfo)
|
not1mm/vfo.py
CHANGED
@@ -14,10 +14,10 @@ import platform
|
|
14
14
|
from json import loads, JSONDecodeError
|
15
15
|
|
16
16
|
import serial
|
17
|
-
from PyQt6 import QtCore,
|
17
|
+
from PyQt6 import QtCore, QtWidgets, uic
|
18
18
|
from PyQt6.QtCore import QTimer
|
19
19
|
from PyQt6.QtWidgets import QDockWidget
|
20
|
-
from PyQt6.QtGui import QColorConstants
|
20
|
+
from PyQt6.QtGui import QColorConstants, QPalette, QColor
|
21
21
|
|
22
22
|
import not1mm.fsutils as fsutils
|
23
23
|
from not1mm.lib.cat_interface import CAT
|
@@ -61,57 +61,45 @@ class VfoWindow(QDockWidget):
|
|
61
61
|
self.poll_rig_timer.timeout.connect(self.poll_radio)
|
62
62
|
self.poll_rig_timer.start(500)
|
63
63
|
|
64
|
-
def setDarkMode(self, dark: bool):
|
65
|
-
"""
|
64
|
+
def setDarkMode(self, dark: bool) -> None:
|
65
|
+
"""Forces a darkmode palette."""
|
66
66
|
|
67
67
|
if dark:
|
68
|
-
darkPalette =
|
69
|
-
darkColor =
|
70
|
-
|
71
|
-
|
72
|
-
darkPalette.setColor(
|
73
|
-
darkPalette.setColor(
|
74
|
-
|
75
|
-
)
|
68
|
+
darkPalette = QPalette()
|
69
|
+
darkColor = QColor(56, 56, 56)
|
70
|
+
disabledColor = QColor(127, 127, 127)
|
71
|
+
darkPalette.setColor(QPalette.ColorRole.Window, darkColor)
|
72
|
+
darkPalette.setColor(QPalette.ColorRole.WindowText, QColorConstants.White)
|
73
|
+
darkPalette.setColor(QPalette.ColorRole.Base, QColor(45, 45, 45))
|
74
|
+
darkPalette.setColor(QPalette.ColorRole.AlternateBase, darkColor)
|
75
|
+
darkPalette.setColor(QPalette.ColorRole.Text, QColorConstants.White)
|
76
|
+
darkPalette.setColor(QPalette.ColorRole.Button, darkColor)
|
77
|
+
darkPalette.setColor(QPalette.ColorRole.ButtonText, QColorConstants.White)
|
78
|
+
darkPalette.setColor(QPalette.ColorRole.BrightText, QColorConstants.Red)
|
79
|
+
darkPalette.setColor(QPalette.ColorRole.Link, QColor(42, 130, 218))
|
80
|
+
darkPalette.setColor(QPalette.ColorRole.Highlight, QColor(42, 130, 218))
|
76
81
|
darkPalette.setColor(
|
77
|
-
|
82
|
+
QPalette.ColorRole.HighlightedText, QColorConstants.Black
|
78
83
|
)
|
79
|
-
darkPalette.setColor(QtGui.QPalette.ColorRole.AlternateBase, darkColor)
|
80
|
-
darkPalette.setColor(QtGui.QPalette.ColorRole.Text, QColorConstants.White)
|
81
84
|
darkPalette.setColor(
|
82
|
-
|
83
|
-
|
85
|
+
QPalette.ColorGroup.Disabled,
|
86
|
+
QPalette.ColorRole.ButtonText,
|
84
87
|
disabledColor,
|
85
88
|
)
|
86
|
-
darkPalette.setColor(QtGui.QPalette.ColorRole.Button, darkColor)
|
87
|
-
darkPalette.setColor(
|
88
|
-
QtGui.QPalette.ColorRole.ButtonText, QColorConstants.White
|
89
|
-
)
|
90
89
|
darkPalette.setColor(
|
91
|
-
|
92
|
-
|
90
|
+
QPalette.ColorGroup.Disabled,
|
91
|
+
QPalette.ColorRole.HighlightedText,
|
93
92
|
disabledColor,
|
94
93
|
)
|
95
94
|
darkPalette.setColor(
|
96
|
-
|
97
|
-
|
98
|
-
darkPalette.setColor(
|
99
|
-
QtGui.QPalette.ColorRole.Link, QtGui.QColor(42, 130, 218)
|
100
|
-
)
|
101
|
-
darkPalette.setColor(
|
102
|
-
QtGui.QPalette.ColorRole.Highlight, QtGui.QColor(42, 130, 218)
|
103
|
-
)
|
104
|
-
darkPalette.setColor(
|
105
|
-
QtGui.QPalette.ColorRole.HighlightedText, QColorConstants.Black
|
106
|
-
)
|
107
|
-
darkPalette.setColor(
|
108
|
-
QtGui.QPalette.ColorGroup.Disabled,
|
109
|
-
QtGui.QPalette.ColorRole.HighlightedText,
|
95
|
+
QPalette.ColorGroup.Disabled,
|
96
|
+
QPalette.ColorRole.Text,
|
110
97
|
disabledColor,
|
111
98
|
)
|
112
99
|
|
113
|
-
self.setPalette(darkPalette)
|
114
100
|
self.current_palette = darkPalette
|
101
|
+
self.setPalette(darkPalette)
|
102
|
+
self.text_color = QColorConstants.White
|
115
103
|
else:
|
116
104
|
palette = self.style().standardPalette()
|
117
105
|
self.current_palette = palette
|
not1mm/voice_keying.py
ADDED
@@ -0,0 +1,100 @@
|
|
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 logging
|
13
|
+
from pathlib import Path
|
14
|
+
|
15
|
+
try:
|
16
|
+
import sounddevice as sd
|
17
|
+
except OSError as exception:
|
18
|
+
print(exception)
|
19
|
+
print("portaudio is not installed")
|
20
|
+
sd = None
|
21
|
+
import soundfile as sf
|
22
|
+
|
23
|
+
from PyQt6.QtCore import QObject, pyqtSignal, QThread
|
24
|
+
|
25
|
+
logger = logging.getLogger("cat_interface")
|
26
|
+
|
27
|
+
|
28
|
+
class Voice(QObject):
|
29
|
+
"""Voice class"""
|
30
|
+
|
31
|
+
ptt_on = pyqtSignal()
|
32
|
+
ptt_off = pyqtSignal()
|
33
|
+
data_path = None
|
34
|
+
current_op = None
|
35
|
+
sounddevice = None
|
36
|
+
voicings = []
|
37
|
+
|
38
|
+
def __init__(self) -> None:
|
39
|
+
super().__init__()
|
40
|
+
"""setup interface"""
|
41
|
+
|
42
|
+
def run(self):
|
43
|
+
while True:
|
44
|
+
keyed = False
|
45
|
+
while len(self.voicings):
|
46
|
+
if not keyed:
|
47
|
+
self.ptt_on.emit()
|
48
|
+
keyed = True
|
49
|
+
filename = self.voicings.pop(0)
|
50
|
+
if Path(filename).is_file():
|
51
|
+
logger.debug("Voicing: %s", filename)
|
52
|
+
data, _fs = sf.read(filename, dtype="float32")
|
53
|
+
# self.ptt_on.emit()
|
54
|
+
try:
|
55
|
+
sd.default.device = self.sounddevice
|
56
|
+
sd.default.samplerate = 44100.0
|
57
|
+
sd.play(data, blocking=True)
|
58
|
+
# _status = sd.wait()
|
59
|
+
# https://snyk.io/advisor/python/sounddevice/functions/sounddevice.PortAudioError
|
60
|
+
except sd.PortAudioError as err:
|
61
|
+
logger.warning("%s", f"{err}")
|
62
|
+
if keyed:
|
63
|
+
self.ptt_off.emit()
|
64
|
+
QThread.msleep(100)
|
65
|
+
|
66
|
+
def voice_string(self, the_string: str) -> None:
|
67
|
+
"""
|
68
|
+
voices string using nato phonetics.
|
69
|
+
|
70
|
+
Parameters
|
71
|
+
----------
|
72
|
+
the_string : str
|
73
|
+
String to voicify.
|
74
|
+
|
75
|
+
Returns
|
76
|
+
-------
|
77
|
+
None
|
78
|
+
"""
|
79
|
+
|
80
|
+
logger.debug("Voicing: %s", the_string)
|
81
|
+
if sd is None:
|
82
|
+
logger.warning("Sounddevice/portaudio not installed.")
|
83
|
+
return
|
84
|
+
# fsutils.USER_DATA_PATH
|
85
|
+
# self.current_op
|
86
|
+
op_path = self.data_path / self.current_op
|
87
|
+
if "[" in the_string:
|
88
|
+
sub_string = the_string.strip("[]").lower()
|
89
|
+
filename = f"{str(op_path)}/{sub_string}.wav"
|
90
|
+
if Path(filename).is_file():
|
91
|
+
self.voicings.append(filename)
|
92
|
+
return
|
93
|
+
for letter in the_string.lower():
|
94
|
+
if letter in "abcdefghijklmnopqrstuvwxyz 1234567890":
|
95
|
+
if letter == " ":
|
96
|
+
letter = "space"
|
97
|
+
filename = f"{str(op_path)}/{letter}.wav"
|
98
|
+
if Path(filename).is_file():
|
99
|
+
logger.debug("Voicing: %s", filename)
|
100
|
+
self.voicings.append(filename)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: not1mm
|
3
|
-
Version: 24.
|
3
|
+
Version: 24.5.1
|
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
|
@@ -31,6 +31,7 @@ Requires-Dist: appdata
|
|
31
31
|
Requires-Dist: Levenshtein
|
32
32
|
|
33
33
|
# Not1MM
|
34
|
+
<!-- markdownlint-disable MD001 MD033 -->
|
34
35
|
|
35
36
|

|
36
37
|
|
@@ -55,16 +56,16 @@ Requires-Dist: Levenshtein
|
|
55
56
|
- [Common installation recipes for Ubuntu and Fedora](#common-installation-recipes-for-ubuntu-and-fedora)
|
56
57
|
- [Ubuntu 22.04 LTS](#ubuntu-2204-lts)
|
57
58
|
- [Ubuntu 23.04](#ubuntu-2304)
|
58
|
-
- [Ubuntu 24.04](#ubuntu-2404)
|
59
|
+
- [Ubuntu 24.04 LTS](#ubuntu-2404-lts)
|
59
60
|
- [Fedora 38 \& 39](#fedora-38--39)
|
60
61
|
- [Fedora 40](#fedora-40)
|
61
62
|
- [Python, PyPI, pip and pipx](#python-pypi-pip-and-pipx)
|
62
63
|
- [Bootstrapping pipx](#bootstrapping-pipx)
|
63
64
|
- [Installing with pipx](#installing-with-pipx)
|
65
|
+
- [Installing from GitHub source](#installing-from-github-source)
|
64
66
|
- [After the install](#after-the-install)
|
65
67
|
- [You may or may not get a warning message like](#you-may-or-may-not-get-a-warning-message-like)
|
66
68
|
- [Or this fan favorite](#or-this-fan-favorite)
|
67
|
-
- [Installing from GitHub source](#installing-from-github-source)
|
68
69
|
- [Various data file locations](#various-data-file-locations)
|
69
70
|
- [Data](#data)
|
70
71
|
- [Config](#config)
|
@@ -179,22 +180,7 @@ I wish to thank those who've contributed to the project.
|
|
179
180
|
|
180
181
|
## Recent Changes
|
181
182
|
|
182
|
-
- [24-
|
183
|
-
- [24-4-25] Limited loop in radio.py, reducing clock cycles used. Moved Log window to the top of the logger.
|
184
|
-
- [24-4-24] Placed CAT control into a thread so disconnecting the radio wouldn't lock up the interface.
|
185
|
-
- [24-4-17] Trap OSError if no sound device. Stop fsutils/appdata from creating useless .not1mm and .username folder structures on Linux platforms.
|
186
|
-
- [24-4-15] checkwindow.py Tighter results. Changed the call selection to use a single click.
|
187
|
-
- [24-4-9-4] Check for portaudio instead of crash boom. Removed empty dockwidget. Tested on Plasma 6.
|
188
|
-
- [24-4-9-3] Ugh. It's not a real day unless you forget to test.
|
189
|
-
- [24-4-9-2] Put back the floatable dock widgets, 'cause Wayland strikes again.
|
190
|
-
- [24-4-9-1] Removed DockWidgetFloatable from the dock widgets since my wee brain can't figure out how to add a dragable window frame to them once they are floating. Added a minimum size for the VFO LCD digits. Defaulted bandmap window to the right.
|
191
|
-
- [24-4-9] Fixed Checkwindow not showing calls from logged contacts.
|
192
|
-
- [24-4-7] Added FT8Watcher class to prep for FT8 support.
|
193
|
-
- [24-4-4-1] Made docking widgets open state persistent.
|
194
|
-
- [24-4-4] Added per-contest echange hint when adding new contest.
|
195
|
-
- [24-4-2] Migrated to PyQt6. I'm sure there are broken things.
|
196
|
-
- [24-4-1-2] Added color text indicators to the Check Partial window. Poached the code from @kyleboyle. Thanks! Fixed the Log, VFO and Check Partial windows to be actual docking widgets. Refocus call field after double clicking on item in the check partial window.
|
197
|
-
- [24-4-1] Removed some un-needed loops and widgets from the check window. Fixed docking to the left side.
|
183
|
+
- [24-5-1] Moved the voice keying into it's own thread.
|
198
184
|
|
199
185
|
See [CHANGELOG.md](CHANGELOG.md) for prior changes.
|
200
186
|
|
@@ -217,6 +203,10 @@ through your distribution's package manager before continuing.
|
|
217
203
|
I've taken the time to install some common Linux distributions into a VM and
|
218
204
|
noted the minimum steps needed to install not1mm.
|
219
205
|
|
206
|
+
<details>
|
207
|
+
|
208
|
+
<summary><b>Ubuntu 22.04 LTS, 23.04 and 24.04 LTS</b></summary>
|
209
|
+
|
220
210
|
#### Ubuntu 22.04 LTS
|
221
211
|
|
222
212
|
```bash
|
@@ -236,7 +226,7 @@ pipx install not1mm
|
|
236
226
|
pipx ensurepath
|
237
227
|
```
|
238
228
|
|
239
|
-
#### Ubuntu 24.04
|
229
|
+
#### Ubuntu 24.04 LTS
|
240
230
|
|
241
231
|
```bash
|
242
232
|
sudo apt update
|
@@ -246,6 +236,12 @@ pip install --break-system-packages not1mm
|
|
246
236
|
source .profile
|
247
237
|
```
|
248
238
|
|
239
|
+
</details>
|
240
|
+
|
241
|
+
<details>
|
242
|
+
|
243
|
+
<summary><b>Fedora 38, 39 and 40</b></summary>
|
244
|
+
|
249
245
|
#### Fedora 38 & 39
|
250
246
|
|
251
247
|
```bash
|
@@ -262,6 +258,9 @@ sudo dnf install python3-pip python3-pyqt6 portaudio
|
|
262
258
|
pip install not1mm
|
263
259
|
```
|
264
260
|
|
261
|
+
</details>
|
262
|
+
<br>
|
263
|
+
|
265
264
|
You can now open a new terminal and type not1mm. On it's first run, it may or
|
266
265
|
may not install a lovely non AI generated icon, which you can later click on to
|
267
266
|
launch the application.
|
@@ -313,6 +312,40 @@ If you need to later update not1mm, you can do so with:
|
|
313
312
|
pipx upgrade not1mm
|
314
313
|
```
|
315
314
|
|
315
|
+
<details>
|
316
|
+
<summary><b>Installing from GitHub source.</b></summary>
|
317
|
+
|
318
|
+
### Installing from GitHub source
|
319
|
+
|
320
|
+
Since this is packaged for PyPI, if you want to work on your own source branch,
|
321
|
+
after cloning from github you would:
|
322
|
+
|
323
|
+
```bash
|
324
|
+
pip install --upgrade pip
|
325
|
+
pip install setuptools
|
326
|
+
pip install build
|
327
|
+
source rebuild.sh
|
328
|
+
```
|
329
|
+
|
330
|
+
from the root directory. This installs a build chain and a local editable copy
|
331
|
+
of not1mm.
|
332
|
+
|
333
|
+
There's two ways to launch the program from the local editable copy.
|
334
|
+
|
335
|
+
You can either be in the root of the source directory and type:
|
336
|
+
|
337
|
+
```bash
|
338
|
+
python not1mm
|
339
|
+
```
|
340
|
+
|
341
|
+
or be in some other directory and just type:
|
342
|
+
|
343
|
+
```bash
|
344
|
+
not1mm
|
345
|
+
```
|
346
|
+
|
347
|
+
</details>
|
348
|
+
|
316
349
|
## After the install
|
317
350
|
|
318
351
|
You can now open a new terminal and type `not1mm`. On it's first run, it may or
|
@@ -344,35 +377,6 @@ For a more permanent solution you can place the line
|
|
344
377
|
`export QT_QPA_PLATFORM=wayland` in your home directories .bashrc file. Then
|
345
378
|
after logging out and back in you should be able to launch it normally.
|
346
379
|
|
347
|
-
### Installing from GitHub source
|
348
|
-
|
349
|
-
Since this is packaged for PyPI, if you want to work on your own source branch,
|
350
|
-
after cloning from github you would:
|
351
|
-
|
352
|
-
```bash
|
353
|
-
pip install --upgrade pip
|
354
|
-
pip install setuptools
|
355
|
-
pip install build
|
356
|
-
source rebuild.sh
|
357
|
-
```
|
358
|
-
|
359
|
-
from the root directory. This installs a build chain and a local editable copy
|
360
|
-
of not1mm.
|
361
|
-
|
362
|
-
There's two ways to launch the program from the local editable copy.
|
363
|
-
|
364
|
-
You can either be in the root of the source directory and type:
|
365
|
-
|
366
|
-
```bash
|
367
|
-
python not1mm
|
368
|
-
```
|
369
|
-
|
370
|
-
or be in some other directory and just type:
|
371
|
-
|
372
|
-
```bash
|
373
|
-
not1mm
|
374
|
-
```
|
375
|
-
|
376
380
|
## Various data file locations
|
377
381
|
|
378
382
|
### Data
|
@@ -482,7 +486,10 @@ onscreen icon for CAT status. Green good, Red bad, Grey neither.
|
|
482
486
|
|
483
487
|
Under the `CW` TAB, There are three options. `cwdaemon`, which normally uses IP
|
484
488
|
`127.0.0.1` and port `6789`. `pywinkeyer` which normally uses IP `127.0.0.1` and
|
485
|
-
|
489
|
+
`CAT` which if your radio supports it, sends Morse characters via rigctld. As far
|
490
|
+
as I can tell rigctld does not support setting the radios internal keyer speed. So
|
491
|
+
the CW speed control widget will not be functional and you'd need to control the
|
492
|
+
keyer speed thru the radios interface.
|
486
493
|
|
487
494
|
### Cluster
|
488
495
|
|