From f0582dc1bda992f9b835024f2b2af817685ecd8e Mon Sep 17 00:00:00 2001 From: mbridak Date: Sun, 20 Oct 2024 19:51:49 -0700 Subject: [PATCH] @mbridak Got rid of the multicast UDP inter-widget messaging scheme. Using signals and methods instead. --- not1mm/__main__.py | 393 +++++++++++++++++++--------------------- not1mm/bandmap.py | 249 +++++++++++++------------ not1mm/checkwindow.py | 88 ++++----- not1mm/logwindow.py | 69 +++---- not1mm/lookupservice.py | 74 ++++---- 5 files changed, 407 insertions(+), 466 deletions(-) diff --git a/not1mm/__main__.py b/not1mm/__main__.py index 0904e9f6..b39ce1a1 100644 --- a/not1mm/__main__.py +++ b/not1mm/__main__.py @@ -16,7 +16,6 @@ import logging from logging.handlers import RotatingFileHandler import os -import platform import socket import sys import uuid @@ -56,7 +55,8 @@ reciprocol, fakefreq, ) -from not1mm.lib.multicast import Multicast + +# from not1mm.lib.multicast import Multicast from not1mm.lib.n1mm import N1MM from not1mm.lib.new_contest import NewContest from not1mm.lib.super_check_partial import SCP @@ -550,6 +550,7 @@ def __init__(self, splash): self.show_splash_msg("Starting LookUp Service.") self.lookup_service = LookupService() + self.lookup_service.message.connect(self.dockwidget_message) self.lookup_service.hide() self.show_splash_msg("Reading preferences.") @@ -583,34 +584,12 @@ def __init__(self, splash): self.voice_process.current_op = self.current_op self.make_op_dir() - self.clearinputs() - self.show_splash_msg("Loading contest.") - self.load_contest() - self.show_splash_msg("Reading macros.") - self.read_cw_macros() - # Featureset for wayland dockfeatures = ( QtWidgets.QDockWidget.DockWidgetFeature.DockWidgetClosable | QtWidgets.QDockWidget.DockWidgetFeature.DockWidgetMovable ) - self.show_splash_msg("Starting FlDigi watcher.") - self.fldigi_watcher = FlDigiWatcher() - self.fldigi_watcher.moveToThread(self.fldigi_thread) - self.fldigi_thread.started.connect(self.fldigi_watcher.run) - self.fldigi_thread.finished.connect(self.fldigi_watcher.deleteLater) - self.fldigi_watcher.poll_callback.connect(self.fldigi_qso) - self.fldigi_thread.start() - - self.show_splash_msg("Setting up LogWindow.") - self.log_window = LogWindow() - self.log_window.setObjectName("log-window") - if os.environ.get("WAYLAND_DISPLAY"): - self.log_window.setFeatures(dockfeatures) - self.addDockWidget(Qt.DockWidgetArea.TopDockWidgetArea, self.log_window) - self.log_window.hide() - self.show_splash_msg("Setting up BandMapWindow.") self.bandmap_window = BandMapWindow() self.bandmap_window.setObjectName("bandmap-window") @@ -619,6 +598,8 @@ def __init__(self, splash): self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, self.bandmap_window) self.bandmap_window.hide() self.bandmap_window.cluster_expire.connect(self.cluster_expire_updated) + self.bandmap_window.message.connect(self.dockwidget_message) + self.bandmap_window.callsignField.setText(self.current_op) self.show_splash_msg("Setting up CheckWindow.") self.check_window = CheckWindow() @@ -627,6 +608,7 @@ def __init__(self, splash): self.check_window.setFeatures(dockfeatures) self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.check_window) self.check_window.hide() + self.check_window.message.connect(self.dockwidget_message) self.show_splash_msg("Setting up VFOWindow.") self.vfo_window = VfoWindow() @@ -636,6 +618,29 @@ def __init__(self, splash): self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.vfo_window) self.vfo_window.hide() + self.show_splash_msg("Setting up LogWindow.") + self.log_window = LogWindow() + self.log_window.setObjectName("log-window") + if os.environ.get("WAYLAND_DISPLAY"): + self.log_window.setFeatures(dockfeatures) + self.addDockWidget(Qt.DockWidgetArea.TopDockWidgetArea, self.log_window) + self.log_window.hide() + self.log_window.message.connect(self.dockwidget_message) + + self.clearinputs() + self.show_splash_msg("Loading contest.") + self.load_contest() + self.show_splash_msg("Reading macros.") + self.read_cw_macros() + + self.show_splash_msg("Starting FlDigi watcher.") + self.fldigi_watcher = FlDigiWatcher() + self.fldigi_watcher.moveToThread(self.fldigi_thread) + self.fldigi_thread.started.connect(self.fldigi_watcher.run) + self.fldigi_thread.finished.connect(self.fldigi_watcher.deleteLater) + self.fldigi_watcher.poll_callback.connect(self.fldigi_qso) + self.fldigi_thread.start() + self.show_splash_msg("Restoring window states.") self.settings = QSettings("K6GTE", "not1mm") if self.settings.value("windowState") is not None: @@ -646,19 +651,28 @@ def __init__(self, splash): self.actionLog_Window.setChecked(self.pref.get("logwindow", False)) if self.actionLog_Window.isChecked(): self.log_window.show() + else: + self.log_window.hide() self.actionBandmap.setChecked(self.pref.get("bandmapwindow", False)) if self.actionBandmap.isChecked(): self.bandmap_window.show() + else: + self.bandmap_window.hide() self.actionCheck_Window.setChecked(self.pref.get("checkwindow", False)) if self.actionCheck_Window.isChecked(): self.check_window.show() self.check_window.setActive(True) + else: + self.check_window.hide() + self.check_window.setActive(False) self.actionVFO.setChecked(self.pref.get("vfowindow", False)) if self.actionVFO.isChecked(): self.vfo_window.show() + else: + self.vfo_window.hide() self.cwspeed_spinbox_changed() @@ -719,6 +733,88 @@ def show_splash_msg(self, msg: str) -> None: ) QCoreApplication.processEvents() + def dockwidget_message(self, msg): + """signal from bandmap""" + if msg: + if msg.get("cmd", "") == "GETCOLUMNS": + if hasattr(self.contest, "columns"): + cmd = {} + cmd["cmd"] = "SHOWCOLUMNS" + cmd["COLUMNS"] = self.contest.columns + if self.log_window: + self.log_window.msg_from_main(cmd) + return + if msg.get("cmd", "") == "TUNE": + # b'{"cmd": "TUNE", "freq": 7.0235, "spot": "MM0DGI"}' + vfo = msg.get("freq") + vfo = float(vfo) * 1000000 + self.radio_state["vfoa"] = int(vfo) + if self.rig_control: + self.rig_control.set_vfo(int(vfo)) + spot = msg.get("spot", "") + self.callsign.setText(spot) + self.callsign_changed() + self.callsign.setFocus() + self.callsign.activateWindow() + return + + if msg.get("cmd", "") == "GETWORKEDLIST": + result = self.database.get_calls_and_bands() + cmd = {} + cmd["cmd"] = "WORKED" + cmd["worked"] = result + if self.bandmap_window: + self.bandmap_window.msg_from_main(cmd) + return + + if msg.get("cmd", "") == "GETCONTESTSTATUS": + cmd = { + "cmd": "CONTESTSTATUS", + "contest": self.contest_settings, + "operator": self.current_op, + } + if self.bandmap_window: + self.bandmap_window.msg_from_main(cmd) + self.bandmap_window.callsignField.setText(self.current_op) + return + + if msg.get("cmd", "") == "CHANGECALL": + self.callsign.setText(msg.get("call", "")) + self.callsign.setFocus() + + if msg.get("cmd", "") == "CHECKSPOTS": + if self.check_window: + self.check_window.msg_from_main(msg) + + # '{"cmd": "LOOKUP_RESPONSE", "station": "fredo", "result": {"call": "K6GTE", "aliases": "KM6HQI", "dxcc": "291", "nickname": "Mike", "fname": "Michael C", "name": "Bridak", "addr1": "2854 W Bridgeport Ave", "addr2": "Anaheim", "state": "CA", "zip": "92804", "country": "United States", "lat": "33.825460", "lon": "-117.987510", "grid": "DM13at", "county": "Orange", "ccode": "271", "fips": "06059", "land": "United States", "efdate": "2021-01-13", "expdate": "2027-11-07", "class": "G", "codes": "HVIE", "email": "michael.bridak@gmail.com", "u_views": "3049", "bio": "7232", "biodate": "2023-04-10 17:56:55", "image": "https://cdn-xml.qrz.com/e/k6gte/qsl.png", "imageinfo": "285:545:99376", "moddate": "2021-04-08 21:41:07", "MSA": "5945", "AreaCode": "714", "TimeZone": "Pacific", "GMTOffset": "-8", "DST": "Y", "eqsl": "0", "mqsl": "1", "cqzone": "3", "ituzone": "6", "born": "1967", "lotw": "1", "user": "K6GTE", "geoloc": "geocode", "name_fmt": "Michael C \\"Mike\\" Bridak"}}' + + if msg.get("cmd", "") == "LOOKUP_RESPONSE": + if msg.get("result", None) is not None: + fname = msg.get("result", {}).get("fname", "") + name = msg.get("result", {}).get("name", "") + grid = msg.get("result", {}).get("grid", "") + nickname = msg.get("result", {}).get("nickname", "") + + if self.contest: + if "General Logging" in self.contest.name: + if nickname: + self.other_1.setText(nickname) + elif fname: + self.other_1.setText(fname) + elif name: + self.other_1.setText(name) + + if grid: + self.contact["GridSquare"] = grid + # _theircountry = response.get("country", "") + if self.station.get("GridSquare", ""): + heading = bearing(self.station.get("GridSquare", ""), grid) + kilometers = distance(self.station.get("GridSquare", ""), grid) + self.heading_distance.setText( + f"{grid} Hdg {heading}° LP {reciprocol(heading)}° / " + f"distance {int(kilometers*0.621371)}mi {kilometers}km" + ) + def cluster_expire_updated(self, number): """signal from bandmap""" self.pref["cluster_expire"] = int(number) @@ -778,8 +874,12 @@ def setDarkMode(self, setdarkmode=False) -> None: cmd = {} cmd["cmd"] = "DARKMODE" cmd["state"] = setdarkmode - cmd["station"] = platform.node() - self.multicast_interface.send_as_json(cmd) + if self.log_window: + self.log_window.msg_from_main(cmd) + if self.bandmap_window: + self.bandmap_window.msg_from_main(cmd) + if self.check_window: + self.check_window.msg_from_main(cmd) if setdarkmode: darkPalette = QPalette() @@ -948,8 +1048,8 @@ def quit_app(self) -> None: cmd = {} cmd["cmd"] = "HALT" - cmd["station"] = platform.node() - self.multicast_interface.send_as_json(cmd) + if self.lookup_service: + self.lookup_service.msg_from_main(cmd) app.quit() def show_message_box(self, message: str) -> None: @@ -1110,8 +1210,8 @@ def new_database(self) -> None: self.make_op_dir() cmd = {} cmd["cmd"] = "NEWDB" - cmd["station"] = platform.node() - self.multicast_interface.send_as_json(cmd) + if self.log_window: + self.log_window.msg_from_main(cmd) self.clearinputs() self.edit_station_settings() @@ -1147,8 +1247,8 @@ def open_database(self) -> None: self.make_op_dir() cmd = {} cmd["cmd"] = "NEWDB" - cmd["station"] = platform.node() - self.multicast_interface.send_as_json(cmd) + if self.log_window: + self.log_window.msg_from_main(cmd) self.clearinputs() self.open_contest() @@ -1436,14 +1536,14 @@ def load_contest(self) -> None: self.clearinputs() cmd = {} cmd["cmd"] = "NEWDB" - cmd["station"] = platform.node() - self.multicast_interface.send_as_json(cmd) + if self.log_window: + self.log_window.msg_from_main(cmd) if hasattr(self.contest, "columns"): cmd = {} cmd["cmd"] = "SHOWCOLUMNS" - cmd["station"] = platform.node() cmd["COLUMNS"] = self.contest.columns - self.multicast_interface.send_as_json(cmd) + if self.log_window: + self.log_window.msg_from_main(cmd) def check_for_new_cty(self) -> None: """ @@ -1721,8 +1821,12 @@ def closeEvent(self, _event) -> None: cmd = {} cmd["cmd"] = "HALT" - cmd["station"] = platform.node() - self.multicast_interface.send_as_json(cmd) + if self.bandmap_window: + self.bandmap_window.msg_from_main(cmd) + if self.log_window: + self.log_window.msg_from_main(cmd) + if self.lookup_service: + self.lookup_service.msg_from_main(cmd) self.write_preference() def cty_lookup(self, callsign: str) -> list: @@ -1802,10 +1906,10 @@ def keyPressEvent(self, event) -> None: # pylint: disable=invalid-name if freq and dx: cmd = {} cmd["cmd"] = "SPOTDX" - cmd["station"] = platform.node() cmd["dx"] = dx cmd["freq"] = float(int(freq) / 1000) - self.multicast_interface.send_as_json(cmd) + if self.bandmap_window: + self.bandmap_window.msg_from_main(cmd) return if ( event.key() == Qt.Key.Key_M @@ -1816,10 +1920,10 @@ def keyPressEvent(self, event) -> None: # pylint: disable=invalid-name if freq and dx: cmd = {} cmd["cmd"] = "MARKDX" - cmd["station"] = platform.node() cmd["dx"] = dx cmd["freq"] = float(int(freq) / 1000) - self.multicast_interface.send_as_json(cmd) + if self.bandmap_window: + self.bandmap_window.msg_from_main(cmd) return if ( event.key() == Qt.Key.Key_G @@ -1829,9 +1933,9 @@ def keyPressEvent(self, event) -> None: # pylint: disable=invalid-name if dx: cmd = {} cmd["cmd"] = "FINDDX" - cmd["station"] = platform.node() cmd["dx"] = dx - self.multicast_interface.send_as_json(cmd) + if self.bandmap_window: + self.bandmap_window.msg_from_main(cmd) return if ( event.key() == Qt.Key.Key_Escape @@ -1856,14 +1960,14 @@ def keyPressEvent(self, event) -> None: # pylint: disable=invalid-name if event.key() == Qt.Key.Key_Up: cmd = {} cmd["cmd"] = "PREVSPOT" - cmd["station"] = platform.node() - self.multicast_interface.send_as_json(cmd) + if self.bandmap_window: + self.bandmap_window.msg_from_main(cmd) return if event.key() == Qt.Key.Key_Down: cmd = {} cmd["cmd"] = "NEXTSPOT" - cmd["station"] = platform.node() - self.multicast_interface.send_as_json(cmd) + if self.bandmap_window: + self.bandmap_window.msg_from_main(cmd) return if ( event.key() == Qt.Key.Key_PageUp @@ -1959,9 +2063,9 @@ def keyPressEvent(self, event) -> None: # pylint: disable=invalid-name text = text.upper() cmd = {} cmd["cmd"] = "LOOKUP_CALL" - cmd["station"] = platform.node() cmd["call"] = text - self.multicast_interface.send_as_json(cmd) + if self.lookup_service: + self.lookup_service.msg_from_main(cmd) next_tab = self.tab_next.get(self.callsign) next_tab.setFocus() next_tab.deselect() @@ -2031,10 +2135,10 @@ def send_worked_list(self) -> None: cmd = {} cmd["cmd"] = "WORKED" - cmd["station"] = platform.node() cmd["worked"] = self.worked_list logger.debug("%s", f"{cmd}") - self.multicast_interface.send_as_json(cmd) + if self.bandmap_window: + self.bandmap_window.msg_from_main(cmd) def clearinputs(self) -> None: """ @@ -2077,9 +2181,13 @@ def clearinputs(self) -> None: self.callsign.setFocus() cmd = {} cmd["cmd"] = "CALLCHANGED" - cmd["station"] = platform.node() cmd["call"] = "" - self.multicast_interface.send_as_json(cmd) + if self.log_window: + self.log_window.msg_from_main(cmd) + if self.bandmap_window: + self.bandmap_window.msg_from_main(cmd) + if self.check_window: + self.check_window.msg_from_main(cmd) def save_contact(self) -> None: """ @@ -2199,8 +2307,10 @@ def save_contact(self) -> None: cmd = {} cmd["cmd"] = "UPDATELOG" - cmd["station"] = platform.node() - self.multicast_interface.send_as_json(cmd) + if self.log_window: + self.log_window.msg_from_main(cmd) + if self.check_window: + self.check_window.msg_from_main(cmd) def new_contest_dialog(self) -> None: """ @@ -2623,17 +2733,10 @@ def readpreferences(self) -> None: else: self.actionMode_and_Bands.setChecked(False) - self.multicast_interface = Multicast( - self.pref.get("multicast_group", "239.1.1.1"), - self.pref.get("multicast_port", 2239), - self.pref.get("interface_ip", "0.0.0.0"), - ) - self.multicast_interface.ready_read_connect(self.watch_udp) - cmd = {} cmd["cmd"] = "REFRESH_LOOKUP" - cmd["station"] = platform.node() - self.multicast_interface.send_as_json(cmd) + if self.lookup_service: + self.lookup_service.msg_from_main(cmd) if self.pref.get("darkmode"): self.actionDark_Mode_2.setChecked(True) @@ -2782,119 +2885,6 @@ def readpreferences(self) -> None: self.esm_dict["MYCALL"] = fkey_dict.get(self.pref.get("esm_mycall", "DISABLED")) self.esm_dict["QSOB4"] = fkey_dict.get(self.pref.get("esm_qsob4", "DISABLED")) - def watch_udp(self) -> None: - """ - Watch the UDP socket for incoming data. - - Parameters - ---------- - None - - Returns - ------- - None - """ - - while self.multicast_interface.has_pending_datagrams(): - json_data = self.multicast_interface.read_datagram_as_json() - if json_data: - if ( - json_data.get("cmd", "") == "GETCOLUMNS" - and json_data.get("station", "") == platform.node() - ): - if hasattr(self.contest, "columns"): - cmd = {} - cmd["cmd"] = "SHOWCOLUMNS" - cmd["station"] = platform.node() - cmd["COLUMNS"] = self.contest.columns - self.multicast_interface.send_as_json(cmd) - continue - if ( - json_data.get("cmd", "") == "TUNE" - and json_data.get("station", "") == platform.node() - ): - # b'{"cmd": "TUNE", "freq": 7.0235, "spot": "MM0DGI"}' - vfo = json_data.get("freq") - vfo = float(vfo) * 1000000 - self.radio_state["vfoa"] = int(vfo) - if self.rig_control: - self.rig_control.set_vfo(int(vfo)) - spot = json_data.get("spot", "") - self.callsign.setText(spot) - self.callsign_changed() - self.callsign.setFocus() - self.callsign.activateWindow() - # This broke somehow. - # window.raise_() - continue - - if ( - json_data.get("cmd", "") == "GETWORKEDLIST" - and json_data.get("station", "") == platform.node() - ): - result = self.database.get_calls_and_bands() - cmd = {} - cmd["cmd"] = "WORKED" - cmd["station"] = platform.node() - cmd["worked"] = result - self.multicast_interface.send_as_json(cmd) - continue - - if ( - json_data.get("cmd", "") == "GETCONTESTSTATUS" - and json_data.get("station", "") == platform.node() - ): - cmd = { - "cmd": "CONTESTSTATUS", - "station": platform.node(), - "contest": self.contest_settings, - "operator": self.current_op, - } - self.multicast_interface.send_as_json(cmd) - continue - - if ( - json_data.get("cmd", "") == "CHANGECALL" - and json_data.get("station", "") == platform.node() - ): - self.callsign.setText(json_data.get("call", "")) - self.callsign.setFocus() - - # '{"cmd": "LOOKUP_RESPONSE", "station": "fredo", "result": {"call": "K6GTE", "aliases": "KM6HQI", "dxcc": "291", "nickname": "Mike", "fname": "Michael C", "name": "Bridak", "addr1": "2854 W Bridgeport Ave", "addr2": "Anaheim", "state": "CA", "zip": "92804", "country": "United States", "lat": "33.825460", "lon": "-117.987510", "grid": "DM13at", "county": "Orange", "ccode": "271", "fips": "06059", "land": "United States", "efdate": "2021-01-13", "expdate": "2027-11-07", "class": "G", "codes": "HVIE", "email": "michael.bridak@gmail.com", "u_views": "3049", "bio": "7232", "biodate": "2023-04-10 17:56:55", "image": "https://cdn-xml.qrz.com/e/k6gte/qsl.png", "imageinfo": "285:545:99376", "moddate": "2021-04-08 21:41:07", "MSA": "5945", "AreaCode": "714", "TimeZone": "Pacific", "GMTOffset": "-8", "DST": "Y", "eqsl": "0", "mqsl": "1", "cqzone": "3", "ituzone": "6", "born": "1967", "lotw": "1", "user": "K6GTE", "geoloc": "geocode", "name_fmt": "Michael C \\"Mike\\" Bridak"}}' - - if ( - json_data.get("cmd", "") == "LOOKUP_RESPONSE" - and json_data.get("station", "") == platform.node() - ): - if json_data.get("result", None) is not None: - fname = json_data.get("result", {}).get("fname", "") - name = json_data.get("result", {}).get("name", "") - grid = json_data.get("result", {}).get("grid", "") - # error_text = json_data.get("result", {}).get("error_text", "") - nickname = json_data.get("result", {}).get("nickname", "") - - if self.contest: - if "General Logging" in self.contest.name: - if nickname: - self.other_1.setText(nickname) - elif fname: - self.other_1.setText(fname) - elif name: - self.other_1.setText(name) - - if grid: - self.contact["GridSquare"] = grid - # _theircountry = response.get("country", "") - if self.station.get("GridSquare", ""): - heading = bearing(self.station.get("GridSquare", ""), grid) - kilometers = distance( - self.station.get("GridSquare", ""), grid - ) - self.heading_distance.setText( - f"{grid} Hdg {heading}° LP {reciprocol(heading)}° / " - f"distance {int(kilometers*0.621371)}mi {kilometers}km" - ) - def dark_mode_state_changed(self) -> None: """Called when the Dark Mode menu state is changed.""" self.pref["darkmode"] = self.actionDark_Mode_2.isChecked() @@ -3097,32 +3087,26 @@ def callsign_changed(self) -> None: self.show_help_dialog() self.clearinputs() return - # if stripped_text == "TEST": - # result = self.database.get_calls_and_bands() - # cmd = {} - # cmd["cmd"] = "WORKED" - # cmd["station"] = platform.node() - # cmd["worked"] = result - # self.multicast_interface.send_as_json(cmd) - # self.clearinputs() - # return if self.is_floatable(stripped_text): self.change_freq(stripped_text) self.clearinputs() return - cmd = {} cmd["cmd"] = "LOOKUP_CALL" - cmd["station"] = platform.node() cmd["call"] = stripped_text - self.multicast_interface.send_as_json(cmd) + if self.lookup_service: + self.lookup_service.msg_from_main(cmd) self.next_field.setFocus() return cmd = {} cmd["cmd"] = "CALLCHANGED" - cmd["station"] = platform.node() cmd["call"] = stripped_text - self.multicast_interface.send_as_json(cmd) + if self.bandmap_window: + self.bandmap_window.msg_from_main(cmd) + if self.log_window: + self.log_window.msg_from_main(cmd) + if self.check_window: + self.check_window.msg_from_main(cmd) self.check_callsign(stripped_text) if self.check_dupe(stripped_text): self.dupe_indicator.show() @@ -3161,10 +3145,10 @@ def change_freq(self, stripped_text: str) -> None: cmd = {} cmd["cmd"] = "RADIO_STATE" - cmd["station"] = platform.node() cmd["band"] = band cmd["vfoa"] = vfo - self.multicast_interface.send_as_json(cmd) + if self.bandmap_window: + self.bandmap_window.msg_from_main(cmd) def change_mode(self, mode: str) -> None: """ @@ -3366,6 +3350,8 @@ def new_op(self) -> None: if self.opon_dialog.NewOperator.text(): self.current_op = self.opon_dialog.NewOperator.text().upper() self.voice_process.current_op = self.current_op + if self.bandmap_window: + self.bandmap_window.callsignField.setText(self.current_op) self.opon_dialog.close() logger.debug("New Op: %s", self.current_op) self.make_op_dir() @@ -3457,18 +3443,26 @@ def poll_radio(self, the_dict): ): self.setmode("RTTY") + cmd = {} + cmd["cmd"] = "RADIO_STATE" + cmd["band"] = band + cmd["vfoa"] = vfo + cmd["mode"] = mode + cmd["bw"] = bw + if self.bandmap_window: + self.bandmap_window.msg_from_main(cmd) if info_dirty: try: logger.debug("VFO: %s MODE: %s BW: %s", vfo, mode, bw) self.set_window_title() cmd = {} cmd["cmd"] = "RADIO_STATE" - cmd["station"] = platform.node() cmd["band"] = band cmd["vfoa"] = vfo cmd["mode"] = mode cmd["bw"] = bw - self.multicast_interface.send_as_json(cmd) + if self.bandmap_window: + self.bandmap_window.msg_from_main(cmd) if self.n1mm: self.n1mm.radio_info["Freq"] = vfo[:-1] self.n1mm.radio_info["TXFreq"] = vfo[:-1] @@ -3478,13 +3472,6 @@ def poll_radio(self, the_dict): self.pref.get("run_state", False) ) if self.n1mm.send_radio_packets: - # self.n1mm.radio_info["Freq"] = vfo[:-1] - # self.n1mm.radio_info["TXFreq"] = vfo[:-1] - # self.n1mm.radio_info["Mode"] = mode - # self.n1mm.radio_info["OpCall"] = self.current_op - # self.n1mm.radio_info["IsRunning"] = str( - # self.pref.get("run_state", False) - # ) self.n1mm.send_radio() except TypeError as err: logger.debug(f"{err=} {vfo=} {the_dict=}") diff --git a/not1mm/bandmap.py b/not1mm/bandmap.py index e56275d9..356ebbf3 100755 --- a/not1mm/bandmap.py +++ b/not1mm/bandmap.py @@ -24,7 +24,8 @@ from PyQt6.QtCore import pyqtSignal import not1mm.fsutils as fsutils -from not1mm.lib.multicast import Multicast + +# from not1mm.lib.multicast import Multicast logger = logging.getLogger(__name__) @@ -160,7 +161,9 @@ def addspot(self, spot: dict, erase=True) -> None: """ try: if erase: - delete_call = "delete from spots where callsign = ?;" + delete_call = ( + "delete from spots where callsign = ? and ts < DATETIME();" + ) self.cursor.execute(delete_call, (spot.get("callsign"),)) self.db.commit() @@ -324,6 +327,7 @@ class BandMapWindow(QDockWidget): multicast_interface = None text_color = QColor(45, 45, 45) cluster_expire = pyqtSignal(str) + message = pyqtSignal(dict) def __init__(self): super().__init__() @@ -357,12 +361,6 @@ def __init__(self): self.update_timer.start(UPDATE_INTERVAL) self.setDarkMode(self.settings.get("darkmode", False)) self.update() - self.multicast_interface = Multicast( - self.settings.get("multicast_group", "239.1.1.1"), - self.settings.get("multicast_port", 2239), - self.settings.get("interface_ip", "0.0.0.0"), - ) - self.multicast_interface.ready_read_connect(self.watch_udp) self.request_workedlist() self.request_contest() @@ -372,6 +370,119 @@ def get_settings(self) -> dict: with open(fsutils.CONFIG_FILE, "rt", encoding="utf-8") as file_descriptor: return loads(file_descriptor.read()) + def msg_from_main(self, packet): + """""" + if packet.get("cmd", "") == "RADIO_STATE": + self.set_band(packet.get("band") + "m", False) + try: + if self.rx_freq != float(packet.get("vfoa")) / 1000000: + self.rx_freq = float(packet.get("vfoa")) / 1000000 + self.tx_freq = self.rx_freq + self.center_on_rxfreq() + except ValueError: + print(f"vfo value error {packet.get('vfoa')}") + logger.debug(f"vfo value error {packet.get('vfoa')}") + return + bw_returned = packet.get("bw", "0") + if not bw_returned.isdigit(): + bw_returned = "0" + self.bandwidth = int(bw_returned) + step, _ = self.determine_step_digits() + self.drawTXRXMarks(step) + return + if packet.get("cmd", "") == "NEXTSPOT" and self.rx_freq: + spot = self.spots.get_next_spot( + self.rx_freq + 0.000001, self.currentBand.end + ) + if spot: + cmd = {} + cmd["cmd"] = "TUNE" + cmd["freq"] = spot.get("freq", self.rx_freq) + cmd["spot"] = spot.get("callsign", "") + self.message.emit(cmd) + return + if packet.get("cmd", "") == "PREVSPOT" and self.rx_freq: + spot = self.spots.get_prev_spot( + self.rx_freq - 0.000001, self.currentBand.start + ) + if spot: + cmd = {} + cmd["cmd"] = "TUNE" + cmd["freq"] = spot.get("freq", self.rx_freq) + cmd["spot"] = spot.get("callsign", "") + self.message.emit(cmd) + return + if packet.get("cmd", "") == "SPOTDX": + dx = packet.get("dx", "") + freq = packet.get("freq", 0.0) + the_UTC_time = datetime.now(timezone.utc).isoformat(" ")[:19].split()[1] + spot = { + "ts": "2099-01-01 " + the_UTC_time, + "callsign": dx, + "freq": freq / 1000, + "band": self.currentBand.name, + "mode": "DX", + "spotter": platform.node(), + "comment": "MARKED", + } + self.spots.addspot(spot, erase=False) + self.update_stations() + return + if packet.get("cmd", "") == "MARKDX": + dx = packet.get("dx", "") + freq = packet.get("freq", 0.0) + the_UTC_time = datetime.now(timezone.utc).isoformat(" ")[:19].split()[1] + spot = { + "ts": "2099-01-01 " + the_UTC_time, + "callsign": dx, + "freq": freq / 1000, + "band": self.currentBand.name, + "mode": "DX", + "spotter": platform.node(), + "comment": "MARKED", + } + self.spots.addspot(spot, erase=False) + self.update_stations() + return + + if packet.get("cmd", "") == "FINDDX": + dx = packet.get("dx", "") + spot = self.spots.get_matching_spot( + dx, self.currentBand.start, self.currentBand.end + ) + if spot: + cmd = {} + cmd["cmd"] = "TUNE" + cmd["freq"] = spot.get("freq", self.rx_freq) + cmd["spot"] = spot.get("callsign", "") + self.message.emit(cmd) + return + if packet.get("cmd", "") == "WORKED": + self.worked_list = packet.get("worked", {}) + logger.debug("%s", f"{self.worked_list}") + return + if packet.get("cmd", "") == "CALLCHANGED": + call = packet.get("call", "") + if call: + result = self.spots.get_like_calls(call) + if result: + cmd = {} + cmd["cmd"] = "CHECKSPOTS" + cmd["spots"] = result + self.message.emit(cmd) + return + cmd = {} + cmd["cmd"] = "CHECKSPOTS" + cmd["spots"] = [] + self.message.emit(cmd) + return + if packet.get("cmd", "") == "CONTESTSTATUS": + if not self.callsignField.text(): + self.callsignField.setText(packet.get("operator", "").upper()) + return + if packet.get("cmd", "") == "DARKMODE": + self.setDarkMode(packet.get("state", False)) + def setDarkMode(self, setdarkmode=False): """Set dark mode""" if setdarkmode: @@ -434,119 +545,6 @@ def connect(self): self.connectButton.setText("Connecting") self.connected = True - def watch_udp(self): - """doc""" - while self.multicast_interface.server_udp.hasPendingDatagrams(): - packet = self.multicast_interface.read_datagram_as_json() - - if packet.get("station", "") != platform.node(): - continue - if packet.get("cmd", "") == "RADIO_STATE": - self.set_band(packet.get("band") + "m", False) - try: - if self.rx_freq != float(packet.get("vfoa")) / 1000000: - self.rx_freq = float(packet.get("vfoa")) / 1000000 - self.tx_freq = self.rx_freq - self.center_on_rxfreq() - except ValueError: - logger.debug(f"vfo value error {packet.get('vfoa')}") - continue - bw_returned = packet.get("bw", "0") - if not bw_returned.isdigit(): - bw_returned = "0" - self.bandwidth = int(bw_returned) - step, _ = self.determine_step_digits() - self.drawTXRXMarks(step) - continue - - if packet.get("cmd", "") == "NEXTSPOT" and self.rx_freq: - spot = self.spots.get_next_spot( - self.rx_freq + 0.000001, self.currentBand.end - ) - if spot: - cmd = {} - cmd["cmd"] = "TUNE" - cmd["station"] = platform.node() - cmd["freq"] = spot.get("freq", self.rx_freq) - cmd["spot"] = spot.get("callsign", "") - self.multicast_interface.send_as_json(cmd) - continue - - if packet.get("cmd", "") == "PREVSPOT" and self.rx_freq: - spot = self.spots.get_prev_spot( - self.rx_freq - 0.000001, self.currentBand.start - ) - if spot: - cmd = {} - cmd["cmd"] = "TUNE" - cmd["station"] = platform.node() - cmd["freq"] = spot.get("freq", self.rx_freq) - cmd["spot"] = spot.get("callsign", "") - self.multicast_interface.send_as_json(cmd) - continue - if packet.get("cmd", "") == "SPOTDX": - dx = packet.get("dx", "") - freq = packet.get("freq", 0.0) - spotdx = f"dx {dx} {freq}" - self.send_command(spotdx) - continue - if packet.get("cmd", "") == "MARKDX": - dx = packet.get("dx", "") - freq = packet.get("freq", 0.0) - the_UTC_time = datetime.now(timezone.utc).isoformat(" ")[:19].split()[1] - spot = { - "ts": "2099-01-01 " + the_UTC_time, - "callsign": dx, - "freq": freq / 1000, - "band": self.currentBand.name, - "mode": "DX", - "spotter": platform.node(), - "comment": "MARKED", - } - self.spots.addspot(spot, erase=False) - self.update_stations() - continue - if packet.get("cmd", "") == "FINDDX": - dx = packet.get("dx", "") - spot = self.spots.get_matching_spot( - dx, self.currentBand.start, self.currentBand.end - ) - if spot: - cmd = {} - cmd["cmd"] = "TUNE" - cmd["station"] = platform.node() - cmd["freq"] = spot.get("freq", self.rx_freq) - cmd["spot"] = spot.get("callsign", "") - self.multicast_interface.send_as_json(cmd) - continue - if packet.get("cmd", "") == "WORKED": - self.worked_list = packet.get("worked", {}) - logger.debug("%s", f"{self.worked_list}") - continue - if packet.get("cmd", "") == "CALLCHANGED": - call = packet.get("call", "") - if call: - result = self.spots.get_like_calls(call) - if result: - cmd = {} - cmd["cmd"] = "CHECKSPOTS" - cmd["station"] = platform.node() - cmd["spots"] = result - self.multicast_interface.send_as_json(cmd) - continue - cmd = {} - cmd["cmd"] = "CHECKSPOTS" - cmd["station"] = platform.node() - cmd["spots"] = [] - self.multicast_interface.send_as_json(cmd) - continue - if packet.get("cmd", "") == "CONTESTSTATUS": - if not self.callsignField.text(): - self.callsignField.setText(packet.get("operator", "").upper()) - continue - if packet.get("cmd", "") == "DARKMODE": - self.setDarkMode(packet.get("state", False)) - def spot_clicked(self): """dunno""" items = self.bandmap_scene.selectedItems() @@ -554,24 +552,21 @@ def spot_clicked(self): if item: cmd = {} cmd["cmd"] = "TUNE" - cmd["station"] = platform.node() cmd["freq"] = items[0].property("freq") cmd["spot"] = items[0].toPlainText().split()[0] - self.multicast_interface.send_as_json(cmd) + self.message.emit(cmd) def request_workedlist(self): """Request worked call list from logger""" cmd = {} cmd["cmd"] = "GETWORKEDLIST" - cmd["station"] = platform.node() - self.multicast_interface.send_as_json(cmd) + self.message.emit(cmd) def request_contest(self): """Request active contest from logger""" cmd = {} cmd["cmd"] = "GETCONTESTSTATUS" - cmd["station"] = platform.node() - self.multicast_interface.send_as_json(cmd) + self.message.emit(cmd) def update_station_timer(self): """doc""" diff --git a/not1mm/checkwindow.py b/not1mm/checkwindow.py index af2941b8..1545c7cb 100644 --- a/not1mm/checkwindow.py +++ b/not1mm/checkwindow.py @@ -11,7 +11,6 @@ import logging import os -import platform import queue from json import loads import Levenshtein @@ -19,10 +18,12 @@ from PyQt6 import uic from PyQt6.QtWidgets import QLabel, QVBoxLayout, QWidget, QDockWidget from PyQt6.QtGui import QMouseEvent, QColorConstants, QPalette, QColor +from PyQt6.QtCore import pyqtSignal import not1mm.fsutils as fsutils from not1mm.lib.database import DataBase -from not1mm.lib.multicast import Multicast + +# from not1mm.lib.multicast import Multicast from not1mm.lib.super_check_partial import SCP logger = logging.getLogger(__name__) @@ -32,6 +33,7 @@ class CheckWindow(QDockWidget): """The check window. Shows list or probable stations.""" multicast_interface = None + message = pyqtSignal(dict) dbname = None pref = {} call = None @@ -59,12 +61,38 @@ def __init__(self): self.mscp = SCP(fsutils.APP_DATA_PATH) self._udpwatch = None self.udp_fifo = queue.Queue() - self.multicast_interface = Multicast( - self.pref.get("multicast_group", "239.1.1.1"), - self.pref.get("multicast_port", 2239), - self.pref.get("interface_ip", "0.0.0.0"), - ) - self.multicast_interface.ready_read_connect(self.watch_udp) + # self.multicast_interface = Multicast( + # self.pref.get("multicast_group", "239.1.1.1"), + # self.pref.get("multicast_port", 2239), + # self.pref.get("interface_ip", "0.0.0.0"), + # ) + # self.multicast_interface.ready_read_connect(self.watch_udp) + + def msg_from_main(self, packet): + """""" + if packet.get("cmd", "") == "DARKMODE": + self.setDarkMode(packet.get("state", False)) + return + if packet.get("cmd", "") == "UPDATELOG": + self.clear_lists() + return + + if self.active is False: + return + if packet.get("cmd", "") == "CALLCHANGED": + call = packet.get("call", "") + self.call = call + self.master_list(call) + self.log_list(call) + return + if packet.get("cmd", "") == "CHECKSPOTS": + self.populate_layout(self.dxcLayout, []) + spots = packet.get("spots", []) + self.telnet_list(spots) + return + if packet.get("cmd", "") == "NEWDB": + ... + # self.load_new_db() def setActive(self, mode: bool): self.active = bool(mode) @@ -74,9 +102,8 @@ def item_clicked(self, item): if item: cmd = {} cmd["cmd"] = "CHANGECALL" - cmd["station"] = platform.node() cmd["call"] = item - self.multicast_interface.send_as_json(cmd) + self.message.emit(cmd) def setDarkMode(self, dark: bool) -> None: """Forces a darkmode palette.""" @@ -145,47 +172,6 @@ def load_pref(self) -> None: logger.critical("Error: %s", exception) self.setDarkMode(self.pref.get("darkmode", False)) - def watch_udp(self): - """ - Puts UDP datagrams in a FIFO queue. - - Parameters - ---------- - None - - Returns - ------- - None - """ - while self.multicast_interface.server_udp.hasPendingDatagrams(): - logger.debug("Got multicast ") - json_data = self.multicast_interface.read_datagram_as_json() - - if json_data.get("station", "") != platform.node(): - continue - if json_data.get("cmd", "") == "DARKMODE": - self.setDarkMode(json_data.get("state", False)) - continue - if json_data.get("cmd", "") == "UPDATELOG": - self.clear_lists() - continue - if self.active is False: - continue - if json_data.get("cmd", "") == "CALLCHANGED": - call = json_data.get("call", "") - self.call = call - self.master_list(call) - self.log_list(call) - continue - if json_data.get("cmd", "") == "CHECKSPOTS": - self.populate_layout(self.dxcLayout, []) - spots = json_data.get("spots", []) - self.telnet_list(spots) - continue - if json_data.get("cmd", "") == "NEWDB": - ... - # self.load_new_db() - def clear_lists(self) -> None: """ Clear match lists. diff --git a/not1mm/logwindow.py b/not1mm/logwindow.py index ecf824f7..429c8033 100755 --- a/not1mm/logwindow.py +++ b/not1mm/logwindow.py @@ -13,7 +13,6 @@ import logging import os -import platform import queue from json import loads @@ -22,11 +21,13 @@ from PyQt6.QtCore import QItemSelectionModel from PyQt6.QtWidgets import QDockWidget from PyQt6.QtGui import QColorConstants, QPalette, QColor +from PyQt6.QtCore import pyqtSignal import not1mm.fsutils as fsutils from not1mm.lib.database import DataBase from not1mm.lib.edit_contact import EditContact -from not1mm.lib.multicast import Multicast + +# from not1mm.lib.multicast import Multicast from not1mm.lib.n1mm import N1MM logger = logging.getLogger(__name__) @@ -62,6 +63,7 @@ class LogWindow(QDockWidget): The main window """ + message = pyqtSignal(dict) multicast_interface = None dbname = None edit_contact_dialog = None @@ -162,18 +164,32 @@ def __init__(self): log.verticalHeader().setVisible(False) self.get_log() - self.multicast_interface = Multicast( - self.pref.get("multicast_group", "239.1.1.1"), - self.pref.get("multicast_port", 2239), - self.pref.get("interface_ip", "0.0.0.0"), - ) - self.multicast_interface.ready_read_connect(self.watch_udp) - cmd = {} cmd["cmd"] = "GETCOLUMNS" - cmd["station"] = platform.node() + self.message.emit(cmd) - self.multicast_interface.send_as_json(cmd) + def msg_from_main(self, msg): + """""" + if msg.get("cmd", "") == "UPDATELOG": + logger.debug("External refresh command.") + self.get_log() + if msg.get("cmd", "") == "CALLCHANGED": + call = msg.get("call", "") + self.show_like_calls(call) + if msg.get("cmd", "") == "NEWDB": + self.load_new_db() + if msg.get("cmd", "") == "SHOWCOLUMNS": + for column in range(len(self.columns)): + self.generalLog.setColumnHidden(column, True) + self.focusedLog.setColumnHidden(column, True) + columns_to_show = msg.get("COLUMNS", []) + for column in columns_to_show: + if column == "Freq": + column = "Freq (Khz)" + self.generalLog.setColumnHidden(self.get_column(column), False) + self.focusedLog.setColumnHidden(self.get_column(column), False) + if msg.get("cmd", "") == "DARKMODE": + self.set_dark_mode(msg.get("state", False)) def resize_headers_to_match(self) -> None: """""" @@ -912,37 +928,6 @@ def get_log(self) -> None: self.generalLog.blockSignals(False) self.focusedLog.blockSignals(False) - def watch_udp(self) -> None: - """ - Watch for UDP datagrams. - Parse commands from our platform.node(). - """ - while self.multicast_interface.server_udp.hasPendingDatagrams(): - json_data = self.multicast_interface.read_datagram_as_json() - - if json_data.get("station", "") != platform.node(): - continue - if json_data.get("cmd", "") == "UPDATELOG": - logger.debug("External refresh command.") - self.get_log() - if json_data.get("cmd", "") == "CALLCHANGED": - call = json_data.get("call", "") - self.show_like_calls(call) - if json_data.get("cmd", "") == "NEWDB": - self.load_new_db() - if json_data.get("cmd", "") == "SHOWCOLUMNS": - for column in range(len(self.columns)): - self.generalLog.setColumnHidden(column, True) - self.focusedLog.setColumnHidden(column, True) - columns_to_show = json_data.get("COLUMNS", []) - for column in columns_to_show: - if column == "Freq": - column = "Freq (Khz)" - self.generalLog.setColumnHidden(self.get_column(column), False) - self.focusedLog.setColumnHidden(self.get_column(column), False) - if json_data.get("cmd", "") == "DARKMODE": - self.set_dark_mode(json_data.get("state", False)) - def show_like_calls(self, call: str) -> None: """ Show all log entries that match call. diff --git a/not1mm/lookupservice.py b/not1mm/lookupservice.py index 08efa05f..e030bb5e 100755 --- a/not1mm/lookupservice.py +++ b/not1mm/lookupservice.py @@ -12,13 +12,14 @@ import logging import os -import platform from json import loads from PyQt6.QtWidgets import QDockWidget +from PyQt6.QtCore import pyqtSignal import not1mm.fsutils as fsutils -from not1mm.lib.multicast import Multicast + +# from not1mm.lib.multicast import Multicast from not1mm.lib.lookup import QRZlookup, HamQTH logger = logging.getLogger(__name__) @@ -27,7 +28,7 @@ class LookupService(QDockWidget): """The Lookup Service class.""" - multicast_interface = None + message = pyqtSignal(dict) def __init__(self): super().__init__() @@ -49,49 +50,36 @@ def __init__(self): self.settings.get("lookuppassword"), ) - self.multicast_interface = Multicast( - self.settings.get("multicast_group", "239.1.1.1"), - self.settings.get("multicast_port", 2239), - self.settings.get("interface_ip", "0.0.0.0"), - ) - self.multicast_interface.ready_read_connect(self.watch_udp) - def get_settings(self) -> dict: """Get the settings.""" if os.path.exists(fsutils.CONFIG_FILE): with open(fsutils.CONFIG_FILE, "rt", encoding="utf-8") as file_descriptor: return loads(file_descriptor.read()) - def watch_udp(self): - """doc""" - while self.multicast_interface.server_udp.hasPendingDatagrams(): - packet = self.multicast_interface.read_datagram_as_json() - - if packet.get("station", "") != platform.node(): - continue - if packet.get("cmd", "") == "LOOKUP_CALL": - if self.look_up: - call = packet.get("call", "") - if call: - result = self.look_up.lookup(call) - cmd = {} - cmd["cmd"] = "LOOKUP_RESPONSE" - cmd["station"] = platform.node() - cmd["result"] = result - self.multicast_interface.send_as_json(cmd) - continue - - if packet.get("cmd", "") == "REFRESH_LOOKUP": - self.settings = self.get_settings() - self.look_up = None - if self.settings.get("useqrz"): - self.look_up = QRZlookup( - self.settings.get("lookupusername"), - self.settings.get("lookuppassword"), - ) - - if self.settings.get("usehamqth"): - self.look_up = HamQTH( - self.settings.get("lookupusername"), - self.settings.get("lookuppassword"), - ) + def msg_from_main(self, packet): + """""" + if packet.get("cmd", "") == "LOOKUP_CALL": + if self.look_up: + call = packet.get("call", "") + if call: + result = self.look_up.lookup(call) + cmd = {} + cmd["cmd"] = "LOOKUP_RESPONSE" + cmd["result"] = result + self.message.emit(cmd) + return + + if packet.get("cmd", "") == "REFRESH_LOOKUP": + self.settings = self.get_settings() + self.look_up = None + if self.settings.get("useqrz"): + self.look_up = QRZlookup( + self.settings.get("lookupusername"), + self.settings.get("lookuppassword"), + ) + + if self.settings.get("usehamqth"): + self.look_up = HamQTH( + self.settings.get("lookupusername"), + self.settings.get("lookuppassword"), + )