not1mm 24.3.16__py3-none-any.whl → 24.3.21__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 +289 -125
- not1mm/bandmap.py +168 -163
- not1mm/checkwindow.py +55 -107
- not1mm/data/MASTER.SCP +1077 -749
- not1mm/data/bandmap.ui +4 -4
- not1mm/data/checkwindow.ui +9 -16
- not1mm/data/logwindow.ui +16 -11
- not1mm/data/main.ui +16 -6
- not1mm/data/vfo.ui +64 -52
- not1mm/data/vfo2.ui +84 -0
- not1mm/fsutils.py +38 -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 +6 -5
- not1mm/lib/version.py +1 -1
- not1mm/logwindow.py +60 -104
- 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 +77 -98
- {not1mm-24.3.16.dist-info → not1mm-24.3.21.dist-info}/METADATA +4 -1
- {not1mm-24.3.16.dist-info → not1mm-24.3.21.dist-info}/RECORD +68 -65
- testing/detectdark.py +35 -0
- testing/test.py +13 -11
- {not1mm-24.3.16.dist-info → not1mm-24.3.21.dist-info}/LICENSE +0 -0
- {not1mm-24.3.16.dist-info → not1mm-24.3.21.dist-info}/WHEEL +0 -0
- {not1mm-24.3.16.dist-info → not1mm-24.3.21.dist-info}/entry_points.txt +0 -0
- {not1mm-24.3.16.dist-info → not1mm-24.3.21.dist-info}/top_level.txt +0 -0
not1mm/bandmap.py
CHANGED
@@ -8,55 +8,25 @@ GPL V3
|
|
8
8
|
# pylint: disable=unused-import, c-extension-no-member, no-member, invalid-name, too-many-lines
|
9
9
|
# pylint: disable=logging-fstring-interpolation, line-too-long
|
10
10
|
|
11
|
-
from datetime import datetime, timezone
|
12
|
-
from decimal import Decimal
|
13
|
-
from json import loads
|
14
|
-
from pathlib import Path
|
15
|
-
|
16
11
|
import logging
|
17
12
|
import os
|
18
|
-
|
19
|
-
# import pkgutil
|
20
13
|
import platform
|
21
|
-
import sys
|
22
14
|
import sqlite3
|
15
|
+
from datetime import datetime, timezone
|
16
|
+
from decimal import Decimal
|
17
|
+
from json import loads
|
23
18
|
|
24
|
-
from PyQt5 import QtCore, QtGui
|
25
|
-
from PyQt5 import
|
26
|
-
from PyQt5 import QtWidgets, uic
|
19
|
+
from PyQt5 import QtCore, QtGui, QtWidgets, uic, QtNetwork
|
20
|
+
from PyQt5.QtCore import Qt
|
27
21
|
|
22
|
+
import not1mm.fsutils as fsutils
|
28
23
|
from not1mm.lib.multicast import Multicast
|
29
24
|
|
30
|
-
|
25
|
+
logger = logging.getLogger(__name__)
|
31
26
|
|
32
27
|
PIXELSPERSTEP = 10
|
33
28
|
UPDATE_INTERVAL = 2000
|
34
29
|
|
35
|
-
# DeprecationWarning: 'pkgutil.get_loader' is deprecated and slated for removal in Python 3.14
|
36
|
-
# loader = pkgutil.get_loader("not1mm")
|
37
|
-
# WORKING_PATH = os.path.dirname(loader.get_filename())
|
38
|
-
WORKING_PATH = os.path.dirname(__loader__.get_filename())
|
39
|
-
|
40
|
-
if "XDG_DATA_HOME" in os.environ:
|
41
|
-
DATA_PATH = os.environ.get("XDG_DATA_HOME")
|
42
|
-
else:
|
43
|
-
DATA_PATH = str(Path.home() / ".local" / "share")
|
44
|
-
DATA_PATH += "/not1mm"
|
45
|
-
|
46
|
-
if "XDG_CONFIG_HOME" in os.environ:
|
47
|
-
CONFIG_PATH = os.environ.get("XDG_CONFIG_HOME")
|
48
|
-
else:
|
49
|
-
CONFIG_PATH = str(Path.home() / ".config")
|
50
|
-
CONFIG_PATH += "/not1mm"
|
51
|
-
|
52
|
-
DARK_STYLESHEET = ""
|
53
|
-
|
54
|
-
PREF = {}
|
55
|
-
if os.path.exists(CONFIG_PATH + "/not1mm.json"):
|
56
|
-
with open(CONFIG_PATH + "/not1mm.json", "rt", encoding="utf-8") as file_descriptor:
|
57
|
-
PREF = loads(file_descriptor.read())
|
58
|
-
|
59
|
-
|
60
30
|
class Band:
|
61
31
|
"""the band"""
|
62
32
|
|
@@ -98,6 +68,8 @@ class Band:
|
|
98
68
|
self.altname = self.othername.get(band, 0.0)
|
99
69
|
|
100
70
|
|
71
|
+
|
72
|
+
|
101
73
|
class Database:
|
102
74
|
"""
|
103
75
|
An in memory Database class to hold spots.
|
@@ -108,18 +80,24 @@ class Database:
|
|
108
80
|
self.db.row_factory = self.row_factory
|
109
81
|
self.cursor = self.db.cursor()
|
110
82
|
sql_command = (
|
111
|
-
"create table spots("
|
112
|
-
"ts DATETIME NOT NULL, "
|
83
|
+
"create table spots ("
|
113
84
|
"callsign VARCHAR(15) NOT NULL, "
|
85
|
+
"ts DATETIME NOT NULL, "
|
114
86
|
"freq DOUBLE NOT NULL, "
|
115
|
-
"band VARCHAR(6), "
|
116
87
|
"mode VARCHAR(6), "
|
117
88
|
"spotter VARCHAR(15) NOT NULL, "
|
118
89
|
"comment VARCHAR(45));"
|
119
90
|
)
|
120
91
|
self.cursor.execute(sql_command)
|
92
|
+
|
93
|
+
self.cursor.execute('CREATE INDEX spot_call_index ON spots (callsign);')
|
94
|
+
self.cursor.execute('CREATE INDEX spot_freq_index ON spots (freq);')
|
95
|
+
self.cursor.execute('CREATE INDEX spot_ts_index ON spots (ts);')
|
96
|
+
|
121
97
|
self.db.commit()
|
122
98
|
|
99
|
+
|
100
|
+
|
123
101
|
@staticmethod
|
124
102
|
def row_factory(cursor, row):
|
125
103
|
"""
|
@@ -175,31 +153,19 @@ class Database:
|
|
175
153
|
If False, do not delete any previous spots with the same callsign.
|
176
154
|
Default is True.
|
177
155
|
|
178
|
-
|
179
156
|
Returns
|
180
157
|
-------
|
181
158
|
Nothing.
|
182
159
|
"""
|
183
160
|
try:
|
184
161
|
if erase:
|
185
|
-
delete_call = (
|
186
|
-
|
187
|
-
)
|
188
|
-
self.cursor.execute(delete_call)
|
162
|
+
delete_call = ("delete from spots where callsign = ?;")
|
163
|
+
self.cursor.execute(delete_call, (spot.get('callsign'),))
|
189
164
|
self.db.commit()
|
190
165
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
placeholders = ""
|
195
|
-
for key in spot.keys():
|
196
|
-
columns += f"{key},"
|
197
|
-
values.append(spot[key])
|
198
|
-
placeholders += "?,"
|
199
|
-
post = f") VALUES({placeholders[:-1]});"
|
200
|
-
|
201
|
-
sql = f"{pre}{columns[:-1]}{post}"
|
202
|
-
self.cursor.execute(sql, tuple(values))
|
166
|
+
self.cursor.execute(
|
167
|
+
"INSERT INTO spots(callsign, ts, freq, mode, spotter, comment) VALUES(?, ?, ?, ?, ?, ?)",
|
168
|
+
(spot['callsign'], spot['ts'], spot['freq'], spot.get('mode', None), spot['spotter'], spot.get('comment', None)))
|
203
169
|
self.db.commit()
|
204
170
|
except sqlite3.IntegrityError:
|
205
171
|
...
|
@@ -239,7 +205,8 @@ class Database:
|
|
239
205
|
A list of dicts.
|
240
206
|
"""
|
241
207
|
self.cursor.execute(
|
242
|
-
|
208
|
+
"select * from spots where freq >= ? and freq <= ? order by freq ASC;",
|
209
|
+
(start, end)
|
243
210
|
)
|
244
211
|
return self.cursor.fetchall()
|
245
212
|
|
@@ -261,7 +228,9 @@ class Database:
|
|
261
228
|
"""
|
262
229
|
|
263
230
|
self.cursor.execute(
|
264
|
-
|
231
|
+
"select * from spots where freq > ? and freq <= ? order by freq ASC;",
|
232
|
+
({current}, limit)
|
233
|
+
|
265
234
|
)
|
266
235
|
return self.cursor.fetchone()
|
267
236
|
|
@@ -284,8 +253,8 @@ class Database:
|
|
284
253
|
"""
|
285
254
|
|
286
255
|
self.cursor.execute(
|
287
|
-
|
288
|
-
|
256
|
+
"select * from spots where freq >= ? and freq <= ? and callsign like ?;",
|
257
|
+
(start, end, f'%{dx}%')
|
289
258
|
)
|
290
259
|
return self.cursor.fetchone()
|
291
260
|
|
@@ -305,7 +274,8 @@ class Database:
|
|
305
274
|
A list of dicts.
|
306
275
|
"""
|
307
276
|
self.cursor.execute(
|
308
|
-
f"select * from spots where freq <
|
277
|
+
f"select * from spots where freq < ? and freq >= ? order by freq DESC;",
|
278
|
+
(current, limit)
|
309
279
|
)
|
310
280
|
return self.cursor.fetchone()
|
311
281
|
|
@@ -323,14 +293,12 @@ class Database:
|
|
323
293
|
None
|
324
294
|
"""
|
325
295
|
self.cursor.execute(
|
326
|
-
f"delete from spots where ts < datetime('now',
|
296
|
+
f"delete from spots where ts < datetime('now', ?);",
|
297
|
+
(f'-{minutes} minutes',)
|
327
298
|
)
|
328
299
|
|
329
300
|
|
330
|
-
class
|
331
|
-
"""
|
332
|
-
The main window
|
333
|
-
"""
|
301
|
+
class BandMapWindow(QtWidgets.QDockWidget):
|
334
302
|
|
335
303
|
zoom = 5
|
336
304
|
currentBand = Band("20m")
|
@@ -346,14 +314,14 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
346
314
|
bandwidth_mark = []
|
347
315
|
worked_list = {}
|
348
316
|
multicast_interface = None
|
317
|
+
text_color = QtGui.QColor(45, 45, 45)
|
349
318
|
|
350
319
|
def __init__(self, *args, **kwargs):
|
351
320
|
super().__init__(*args, **kwargs)
|
352
321
|
self._udpwatch = None
|
353
|
-
|
354
|
-
uic.loadUi(
|
355
|
-
|
356
|
-
self.setStyleSheet(DARK_STYLESHEET)
|
322
|
+
|
323
|
+
uic.loadUi(fsutils.APP_DATA_PATH / "bandmap.ui", self)
|
324
|
+
self.settings = self.get_settings()
|
357
325
|
self.agetime = self.clear_spot_olderSpinBox.value()
|
358
326
|
self.clear_spot_olderSpinBox.valueChanged.connect(self.spot_aging_changed)
|
359
327
|
self.clearButton.clicked.connect(self.clear_spots)
|
@@ -375,35 +343,74 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
375
343
|
self.update_timer = QtCore.QTimer()
|
376
344
|
self.update_timer.timeout.connect(self.update_station_timer)
|
377
345
|
self.update_timer.start(UPDATE_INTERVAL)
|
346
|
+
self.setDarkMode(self.settings.get("darkmode", False))
|
378
347
|
self.update()
|
379
348
|
self.multicast_interface = Multicast(
|
380
|
-
|
381
|
-
|
382
|
-
|
349
|
+
self.settings.get("multicast_group", "239.1.1.1"),
|
350
|
+
self.settings.get("multicast_port", 2239),
|
351
|
+
self.settings.get("interface_ip", "0.0.0.0"),
|
383
352
|
)
|
384
353
|
self.multicast_interface.ready_read_connect(self.watch_udp)
|
385
354
|
self.request_workedlist()
|
355
|
+
self.request_contest()
|
356
|
+
|
357
|
+
|
358
|
+
def get_settings(self) -> dict:
|
359
|
+
if os.path.exists(fsutils.CONFIG_FILE):
|
360
|
+
with open(fsutils.CONFIG_FILE, "rt", encoding="utf-8") as file_descriptor:
|
361
|
+
return loads(file_descriptor.read())
|
362
|
+
|
363
|
+
def setDarkMode(self, setdarkmode=False):
|
364
|
+
"""testing"""
|
365
|
+
|
366
|
+
if setdarkmode:
|
367
|
+
darkPalette = QtGui.QPalette()
|
368
|
+
darkColor = QtGui.QColor(45, 45, 45)
|
369
|
+
self.text_color = Qt.white
|
370
|
+
disabledColor = QtGui.QColor(127, 127, 127)
|
371
|
+
darkPalette.setColor(QtGui.QPalette.Window, darkColor)
|
372
|
+
darkPalette.setColor(QtGui.QPalette.WindowText, Qt.white)
|
373
|
+
darkPalette.setColor(QtGui.QPalette.Base, QtGui.QColor(18, 18, 18))
|
374
|
+
darkPalette.setColor(QtGui.QPalette.AlternateBase, darkColor)
|
375
|
+
darkPalette.setColor(QtGui.QPalette.Text, Qt.white)
|
376
|
+
darkPalette.setColor(
|
377
|
+
QtGui.QPalette.Disabled, QtGui.QPalette.Text, disabledColor
|
378
|
+
)
|
379
|
+
darkPalette.setColor(QtGui.QPalette.Button, darkColor)
|
380
|
+
darkPalette.setColor(QtGui.QPalette.ButtonText, Qt.white)
|
381
|
+
darkPalette.setColor(
|
382
|
+
QtGui.QPalette.Disabled, QtGui.QPalette.ButtonText, disabledColor
|
383
|
+
)
|
384
|
+
darkPalette.setColor(QtGui.QPalette.BrightText, Qt.red)
|
385
|
+
darkPalette.setColor(QtGui.QPalette.Link, QtGui.QColor(42, 130, 218))
|
386
|
+
darkPalette.setColor(QtGui.QPalette.Highlight, QtGui.QColor(42, 130, 218))
|
387
|
+
darkPalette.setColor(QtGui.QPalette.HighlightedText, Qt.black)
|
388
|
+
darkPalette.setColor(
|
389
|
+
QtGui.QPalette.Disabled, QtGui.QPalette.HighlightedText, disabledColor
|
390
|
+
)
|
386
391
|
|
387
|
-
|
388
|
-
|
389
|
-
|
392
|
+
self.setPalette(darkPalette)
|
393
|
+
self.callsignField.setPalette(darkPalette)
|
394
|
+
self.update()
|
395
|
+
else:
|
396
|
+
palette = self.style().standardPalette()
|
397
|
+
self.setPalette(palette)
|
398
|
+
self.callsignField.setPalette(palette)
|
399
|
+
self.text_color = Qt.black
|
400
|
+
self.update()
|
390
401
|
|
391
402
|
def connect(self):
|
392
|
-
|
403
|
+
if not self.callsignField.text():
|
404
|
+
self.callsignField.setFocus()
|
405
|
+
return
|
393
406
|
if self.connected is True:
|
394
|
-
self.
|
395
|
-
self.connected = False
|
396
|
-
self.connectButton.setStyleSheet("color: red;")
|
397
|
-
self.connectButton.setText("Closed")
|
407
|
+
self.close_cluster()
|
398
408
|
return
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
server = PREF.get("cluster_server", "dxc.nc7j.com")
|
405
|
-
port = PREF.get("cluster_port", 7373)
|
406
|
-
logger.debug("%s", f"{server} {port}")
|
409
|
+
# refresh settings
|
410
|
+
self.settings = self.get_settings()
|
411
|
+
server = self.settings.get("cluster_server", "dxc.nc7j.com")
|
412
|
+
port = self.settings.get("cluster_port", 7373)
|
413
|
+
logger.info(f"connecting to dx cluster {server} {port}")
|
407
414
|
self.socket.connectToHost(server, port)
|
408
415
|
self.connectButton.setStyleSheet("color: white;")
|
409
416
|
self.connectButton.setText("Connecting")
|
@@ -514,8 +521,13 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
514
521
|
cmd["spots"] = []
|
515
522
|
self.multicast_interface.send_as_json(cmd)
|
516
523
|
continue
|
517
|
-
if packet.get("cmd", "") == "
|
518
|
-
self.
|
524
|
+
if packet.get("cmd", "") == "CONTESTSTATUS":
|
525
|
+
if not self.callsignField.text():
|
526
|
+
self.callsignField.setText(packet.get("operator", "").upper())
|
527
|
+
self.callsignField.selectAll()
|
528
|
+
continue
|
529
|
+
if packet.get("cmd", "") == "DARKMODE":
|
530
|
+
self.setDarkMode(packet.get("state", False))
|
519
531
|
|
520
532
|
def spot_clicked(self):
|
521
533
|
"""dunno"""
|
@@ -536,13 +548,23 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
536
548
|
cmd["station"] = platform.node()
|
537
549
|
self.multicast_interface.send_as_json(cmd)
|
538
550
|
|
551
|
+
def request_contest(self):
|
552
|
+
"""Request active contest from logger"""
|
553
|
+
cmd = {}
|
554
|
+
cmd["cmd"] = "GETCONTESTSTATUS"
|
555
|
+
cmd["station"] = platform.node()
|
556
|
+
self.multicast_interface.send_as_json(cmd)
|
557
|
+
|
539
558
|
def update_station_timer(self):
|
540
559
|
"""doc"""
|
541
560
|
self.update_stations()
|
542
561
|
|
543
562
|
def update(self):
|
544
563
|
"""doc"""
|
545
|
-
|
564
|
+
try:
|
565
|
+
self.update_timer.setInterval(UPDATE_INTERVAL)
|
566
|
+
except AttributeError:
|
567
|
+
...
|
546
568
|
self.clear_all_callsign_from_scene()
|
547
569
|
self.clear_freq_mark(self.rxMark)
|
548
570
|
self.clear_freq_mark(self.txMark)
|
@@ -562,12 +584,13 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
562
584
|
i * PIXELSPERSTEP,
|
563
585
|
length + 10,
|
564
586
|
i * PIXELSPERSTEP,
|
565
|
-
QtGui.QPen(
|
587
|
+
QtGui.QPen(self.text_color),
|
566
588
|
)
|
567
589
|
if i % 5 == 0: # Add Frequency
|
568
590
|
freq = self.currentBand.start + step * i
|
569
591
|
text = f"{freq:.3f}"
|
570
592
|
self.something = self.bandmap_scene.addText(text)
|
593
|
+
self.something.setDefaultTextColor(self.text_color)
|
571
594
|
self.something.setPos(
|
572
595
|
-(self.something.boundingRect().width()) + 10,
|
573
596
|
i * PIXELSPERSTEP - (self.something.boundingRect().height() / 2),
|
@@ -610,7 +633,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
610
633
|
|
611
634
|
def Freq2ScenePos(self, freq: float):
|
612
635
|
"""doc"""
|
613
|
-
if freq < self.currentBand.start or freq > self.currentBand.end:
|
636
|
+
if not freq or freq < self.currentBand.start or freq > self.currentBand.end:
|
614
637
|
return QtCore.QPointF()
|
615
638
|
step, _digits = self.determine_step_digits()
|
616
639
|
ret = QtCore.QPointF(
|
@@ -687,16 +710,21 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
687
710
|
def update_stations(self):
|
688
711
|
"""doc"""
|
689
712
|
self.update_timer.setInterval(UPDATE_INTERVAL)
|
713
|
+
if not self.connected:
|
714
|
+
return
|
715
|
+
|
690
716
|
self.clear_all_callsign_from_scene()
|
691
717
|
self.spot_aging()
|
692
718
|
step, _digits = self.determine_step_digits()
|
693
719
|
|
694
720
|
result = self.spots.getspotsinband(self.currentBand.start, self.currentBand.end)
|
721
|
+
logger.debug(f"{len(result)} spots in range {self.currentBand.start} - {self.currentBand.end}")
|
722
|
+
|
695
723
|
entity = ""
|
696
724
|
if result:
|
697
725
|
min_y = 0.0
|
698
726
|
for items in result:
|
699
|
-
pen_color =
|
727
|
+
pen_color = self.text_color
|
700
728
|
if items.get("comment") == "MARKED":
|
701
729
|
pen_color = QtGui.QColor(47, 47, 255)
|
702
730
|
if items.get("callsign") in self.worked_list:
|
@@ -786,44 +814,41 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
786
814
|
currentPolygon.clear()
|
787
815
|
|
788
816
|
def receive(self):
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
self.connectButton.setStyleSheet("color: green;")
|
825
|
-
self.connectButton.setText("Connected")
|
826
|
-
logger.debug("%s", f"{data}")
|
817
|
+
while self.socket.bytesAvailable():
|
818
|
+
data = self.socket.readLine(1000)
|
819
|
+
data = str(data, "utf-8").strip()
|
820
|
+
#logger.debug(f"cluster recv line: {data}")
|
821
|
+
|
822
|
+
if "login:" in data or "call:" in data or "callsign:" in data:
|
823
|
+
self.send_command(self.callsignField.text())
|
824
|
+
self.send_command(self.settings.get("cluster_filter", ""))
|
825
|
+
self.send_command("set dx extension Section")
|
826
|
+
self.send_command("set dx mode " + self.settings.get("cluster_mode", "OPEN"))
|
827
|
+
return
|
828
|
+
if "DX de" in data:
|
829
|
+
parts = data.split()
|
830
|
+
spotter = parts[2]
|
831
|
+
freq = parts[3]
|
832
|
+
dx = parts[4]
|
833
|
+
_time = parts[-1]
|
834
|
+
comment = " ".join(parts[5:-1])
|
835
|
+
# spot = DxSpot()
|
836
|
+
spot = {}
|
837
|
+
spot["ts"] = datetime.now(timezone.utc).isoformat(" ")[:19]
|
838
|
+
spot["callsign"] = dx
|
839
|
+
spot["spotter"] = spotter
|
840
|
+
spot["comment"] = comment
|
841
|
+
logger.debug(f"{spot}")
|
842
|
+
try:
|
843
|
+
spot["freq"] = float(freq) / 1000
|
844
|
+
self.spots.addspot(spot)
|
845
|
+
except ValueError:
|
846
|
+
logger.debug(f"couldn't parse freq from datablock {data}")
|
847
|
+
return
|
848
|
+
if self.callsignField.text().upper() in data:
|
849
|
+
self.connectButton.setStyleSheet("color: green;")
|
850
|
+
self.connectButton.setText("Connected")
|
851
|
+
logger.debug(f"callsign login acknowledged {data}")
|
827
852
|
|
828
853
|
def maybeconnected(self):
|
829
854
|
"""doc"""
|
@@ -860,33 +885,13 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
860
885
|
def showContextMenu(self):
|
861
886
|
"""doc"""
|
862
887
|
|
888
|
+
def close_cluster(self):
|
889
|
+
if self.socket and self.socket.isOpen():
|
890
|
+
logger.info("Closing dx cluster connection")
|
891
|
+
self.socket.close()
|
892
|
+
self.connected = False
|
893
|
+
self.connectButton.setStyleSheet("color: red;")
|
894
|
+
self.connectButton.setText("Closed")
|
863
895
|
|
864
|
-
def
|
865
|
-
|
866
|
-
sys.exit(app.exec())
|
867
|
-
|
868
|
-
|
869
|
-
logger = logging.getLogger("__main__")
|
870
|
-
handler = logging.StreamHandler()
|
871
|
-
formatter = logging.Formatter(
|
872
|
-
datefmt="%H:%M:%S",
|
873
|
-
fmt="[%(asctime)s] %(levelname)s %(module)s - %(funcName)s Line %(lineno)d:\n%(message)s",
|
874
|
-
)
|
875
|
-
handler.setFormatter(formatter)
|
876
|
-
logger.addHandler(handler)
|
877
|
-
|
878
|
-
if Path("./debug").exists():
|
879
|
-
logger.setLevel(logging.DEBUG)
|
880
|
-
logger.debug("debugging on")
|
881
|
-
else:
|
882
|
-
logger.setLevel(logging.WARNING)
|
883
|
-
logger.warning("debugging off")
|
884
|
-
|
885
|
-
app = QtWidgets.QApplication(sys.argv)
|
886
|
-
|
887
|
-
|
888
|
-
app.setStyle("Adwaita-Dark")
|
889
|
-
window = MainWindow()
|
890
|
-
window.show()
|
891
|
-
if __name__ == "__main__":
|
892
|
-
run()
|
896
|
+
def closeEvent(self, event: QtGui.QCloseEvent) -> None:
|
897
|
+
self.close_cluster()
|