Example #1
0
    def find_channel_for_controller(self, controllerMac: str,
                                    controllerName: str, vfo: str,
                                    cardAddress: int) -> None:

        response = {
            "address": cardAddress,
            "controllerMac": controllerMac,
            "controllerName": controllerName,
            "vfo": vfo,
            "status": "failed"
        }

        if controllerMac:
            # Attempting to take control of transverter
            try:
                channel = self.get_free_channels()[0]
            except IndexError:
                channel = None

            if channel and channel.request_card_control(cardAddress):
                channel.set_controller(controllerMac, controllerName, vfo)
                response["status"] = "success"
                response["channel"] = channel.name
        else:
            # Attempting to release transverter
            for x in self.channels:
                if x.cardAddress == cardAddress:
                    if x.close_card_control():
                        response["status"] = "success"

        self.mqtt.publish("/{}/requestResponse".format(get_mac()),
                          json.dumps(response))
Example #2
0
    def __init__(self, ipAddr, ipPort, warnings):
        self.warnings = warnings
        self.client = mqtt.Client()
        self.client.on_connect = self.on_connect
        self.client.on_message = self.on_message
        self.ipAddr = ipAddr
        self.ipPort = ipPort
        self.callbacks = {}

        try:
            x = {
                "mac": "{}".format(get_mac()),
                "name": "{}".format(NAME)
            }
            self.client.will_set("/discovery/lwt", json.dumps(x))
            self.client.connect(ipAddr, ipPort, keepalive=5)
            self.client.loop_start()
        except socket.timeout:
            self.warnings.add_error(
                NAME,
                "MQTT",
                "Broker not found at at {}:{}".format(
                    self.ipAddr,
                    self.ipPort
                ),
                broadcast=False
            )
Example #3
0
    def send_discovery_info(self, msg):
        """
        Publishes all the discovery info to the "discovery/info" topic
        Takes message argument as all callback functions must take a message
        but is useless - anything sent to this topic will result in discovery
        information being sent.

        Args:
            msg (str): payload of discovery message. Does nothing with this
                but all MQTT callbacks take this argument

        Returns:
            None

        Raises:
            None

        """
        x = {
            "type": "controller",
            "mac": get_mac(),
            "ip": get_ip(),
            "name": config_user.NAME,
            "api": MQTT_API_VERSION,
            "link": get_link_speed()
        }

        self.mqtt.publish("/discovery/info", json.dumps(x))
Example #4
0
    def process_transverter_control_request_response(self, msg):
        self.transverterMutex.acquire()
        self.transverterResponse = msg
        if (msg["status"] == "success" and msg["controllerMac"] == get_mac()
                and msg["vfo"] == self.name):
            self.sdrChannel = msg["channel"]

        self.transverterMutex.release()
        self.transverterResponded.set()
Example #5
0
    def request_transverter_control(self, transverter: Transverter) -> bool:
        """ Requests control of a specific transverter """
        if self.transverter:
            self.surrender_transverter_control()

        assert self.transverter is None
        assert self.sdrChannel is None

        logging.info('Attempting to take control of transverter "{}"'.format(
            transverter.name))

        self.transverterMutex.release()

        self.mqtt.register_callback(
            "/{}/requestResponse".format(transverter.sdrMac),
            self.process_transverter_control_request_response,
            requiresMainThread=False)

        self.transverterResponded.clear()

        try:
            self.mqtt.publish(
                "/{}/requests".format(transverter.sdrMac),
                json.dumps({
                    "address": transverter.address,
                    "controllerName": NAME,
                    "controllerMac": get_mac(),
                    "vfo": self.name
                }))
            if not self.transverterResponded.wait(timeout=5):
                # Requested timed out
                self.warnings.add_warning(
                    NAME, "MQTT",
                    f"Timed out waiting for response from {transverter.sdrMac}"
                )
            else:
                # Got here so SDR responded, self.sdrChannel now either
                # contains the channel name if everything was successfuly
                # or None if it failed
                if self.sdrChannel:
                    self.transverter = transverter
                    self.mqttTopic = "/{}/channel{}".format(
                        transverter.sdrMac, self.sdrChannel)
                    self.mqtt.register_callback(self.mqttTopic, self.rx_status)
                else:
                    # SDR responded but refused connection
                    self.warnings.add_warning(
                        NAME, "MQTT",
                        f"Refused transverter control by {transverter.sdrMac}")

        finally:
            self.mqtt.remove_callback("/{}/requestResponse".format(
                transverter.sdrMac))
            self.transverterMutex.acquire()

        return bool(self.transverter)
Example #6
0
    def __init__(self, jsonDict, warningHandler: WarningHandler,
                 tabWidget: QTabWidget):
        """
        Base class for any object on the MQTT network
        """

        self.ipAddr = jsonDict['ip']
        self.mac = jsonDict['mac']
        self.name = jsonDict['name']
        self.apiVersion = jsonDict['api']
        self.warningHandler = warningHandler
        self.uptime = ""
        self.linkSpeed = jsonDict['link']
        self._tabWidget = tabWidget
        self.updated = False  # Flag if any info has been updated
        self.warnings = []
        self.errors = []
        self.state = None

        # Create tab in the tab widget for this device
        self._tab = QWidget(self._tabWidget)
        if (self.mac == get_mac()):
            # Ensure that the controller in use goes first
            self._tabWidget.insertTab(0, self._tab,
                                      f"{self.name}\n{self.ipAddr}")
        else:
            # Other device, put at end
            self._tabWidget.addTab(self._tab, f"{self.name}\n{self.ipAddr}")
        self._horizontalLayout = QHBoxLayout(self._tab)
        self._grid = QGridLayout()
        self._iconLayout = QVBoxLayout()
        self._horizontalLayout.addLayout(self._grid)
        self._horizontalLayout.addLayout(self._iconLayout)
        self._horizontalLayout.setStretchFactor(self._iconLayout, 1)

        self._ipLabel = self.add_value_row("IP Address:", self.ipAddr)

        # These are the definition of a unique device so never need updating
        self.add_value_row("Type:", self.get_type())
        self.add_value_row("MAC Address:", self.mac)

        self._apiLabel = self.add_value_row("MQTT API Version:",
                                            self.apiVersion)

        self._uptimeLabel = self.add_value_row("Uptime:", self.uptime)
        self._onlineLabel = self.add_value_row("Online:", "")
        self._update_online_state(True)
        self._linkSpeedLabel = self.add_value_row(
            "Link Speed:",
            str(self.linkSpeed) + " Mbps")

        self._grid.setRowStretch(self._grid.rowCount(), 1)
        self._tab.setLayout(self._horizontalLayout)
Example #7
0
    def __init__(self,
                 name,
                 mqtt,
                 statusregs,
                 warnings: WarningHandler,
                 cards: CardHandler,
                 mode="LSB",
                 freq=28000000,
                 adcClk=80e6,
                 supportsRx=True,
                 supportsTx=False,
                 supportsDuplex=False):
        self.name = name
        self.mqtt = mqtt
        self.statusregs = statusregs
        self.warnings = warnings
        self.cards = cards
        self.supportedModes = {
            "LSB": self.LSB,
            "USB": self.USB,
            "CW": self.CW,
            "Tone": self.TONE
        }
        self.offset = 0
        self.adcClk = adcClk
        self.setTopic = "/{}/channel{}/set".format(get_mac(), self.name)
        self.broadcastTopic = "/{}/channel{}".format(get_mac(), self.name)
        self.set_freq(freq, update=False)
        self.set_mode(mode)
        self.supportsRx = supportsRx
        self.supportsTx = supportsTx
        self.supportsDuplex = supportsDuplex
        if supportsDuplex:
            assert supportsRx and supportsTx
        self.controllerMac = None
        self.controllerName = None
        self.vfo = None
        self.cardAddress = None

        self.mqtt.register_callback(self.setTopic, self.handle_command)
Example #8
0
    def send_status_info(self, msg: str) -> None:
        """
        Publishes all the status info to the "status/info" topic
        Takes message argument as all callback functions must take a message
        but is useless - anything sent to this topic will result in status
        information being sent.

        Args:
            msg (str): payload of status message. Does nothing with this
                but all MQTT callbacks take this argument
        """
        x = {
            "type": "controller",
            "mac": get_mac(),
            "uptime": self.get_uptime()
        }

        self.mqtt.publish("/status/info", json.dumps(x))
Example #9
0
    def send_status_info(self, _: dict = None) -> None:
        """
        Publishes all the discovery info to the "discovery/info" topic
        Takes message argument as all callback functions must take a message
        but is useless - anything sent to this topic will result in discovery
        information being sent.

        Args:
            _ (str): All MQTT callbacks get passed the message. The contents is
                irrelevant here
        """
        x = {
            "type": "sdr",
            "mac": get_mac(),
            "warnings": self.warnings.get_warnings(),
            "errors": self.warnings.get_errors(),
            "uptime": self.get_uptime(),
            "channels": self.channels.get_status_info(),
            "cards": self.cards.get_all_status_info()
        }

        self.mqtt.publish("/status/info", json.dumps(x))
Example #10
0
    def __init__(self, ipAddr, ipPort, warnings):
        super().__init__()
        self.client = mqtt.Client()
        self.client.on_connect = self.on_connect
        self.client.on_message = self.on_message
        self.warnings = warnings
        self.ipAddr = ipAddr
        self.ipPort = ipPort
        self.callbacks = {}

        try:
            x = {"mac": "{}".format(get_mac()), "name": "{}".format(NAME)}
            self.client.will_set("/discovery/lwt", json.dumps(x))
            self.client.connect(ipAddr, ipPort, keepalive=5)
            self.client.loop_start()
            self.messageReceived.connect(self.message_handler)

        except (socket.timeout, ConnectionRefusedError):
            self.warnings.add_error(
                NAME,
                "MQTT",
                f"Broker not found at at {self.ipAddr}:{self.ipPort}",
                broadcast=False)
Example #11
0
    def send_discovery_info(self, _: dict = None) -> None:
        """
        Publishes all the discovery info to the "discovery/info" topic
        Takes message argument as all callback functions must take a message
        but is useless - anything sent to this topic will result in discovery
        information being sent.

        Args:
            _ (dict): All MQTT callbacks get passed the message. The contents
                is irrelevant here
        """
        x = {
            "type": "sdr",
            "ip": get_ip(),
            "mac": get_mac(),
            "name": NAME,
            "api": MQTT_API_VERSION,
            "link": get_link_speed(),
            "numSlots": self.cards.numSlots,
            "channels": self.channels.get_discovery_info(),
            "cards": self.cards.get_all_discovery_info(),
        }

        self.mqtt.publish("/discovery/info", json.dumps(x))
Example #12
0
 def update_mac(self):
     self.ui.label_mac.setText(get_mac())
Example #13
0
    def __init__(self):

        logging.info("Application started. Waiting for NTP sync...")
        client = ntplib.NTPClient()
        while True:
            try:
                response = client.request(NTP_SERVER)
                if (response.offset < 1):
                    # We have a valid NTP time and are within 1s of it
                    break
            except (ntplib.NTPException, socket.gaierror):
                logging.info("NTP Sync failed. Retrying...")
            time.sleep(1)

        logging.info(
            "NTP sync successful. IP Address: {}. "
            "Starting main application".format(get_ip())
        )
        self.startTime = datetime.now(timezone.utc)
        LED_STATUS.write(GPIO.HIGH)
        with WarningHandler() as self.warnings, \
                MqttHandler(
                    MQTT_SERVER_IP_ADDRESS,
                    MQTT_SERVER_PORT,
                    self.warnings
                ) as self.mqtt:

            self.warnings.register_mqtt(self.mqtt)

            self.status = StatusRegs(
                STATUS_REGISTERS_FILE, self.warnings
            )
            self.slots = slotsEeprom(
                SLOTS_I2C_FILE, "Baseboard Config",
                SLOTS_EEPROM_ADDRESS, PIN_WP, self.warnings
            )

            with \
                    CardHandler(
                        TRANSVERTER_RS485_UART,
                        numSlots=self.slots.num_slots()
                    ) as self.cards, \
                    \
                    ChannelHandler(channels=[
                        ChannelPrototype(
                            name='A', supportsRx=True, supportsTx=True
                        )
                    ], cards=self.cards, mqtt=self.mqtt,
                    warnings=self.warnings, status=self.status
                        ) as self.channels:

                self.mqtt.register_callback(
                    "/discovery/request",
                    self.send_discovery_info
                )

                self.mqtt.register_callback(
                    "/status/request",
                    self.send_status_info
                )

                self.mqtt.register_callback(
                    "/discovery/lwt",
                    self.handle_lwt
                )

                self.mqtt.register_callback(
                    "/{}/requests".format(get_mac()),
                    self.handle_control_request
                )

                self.send_discovery_info()
                self.send_status_info()

                self.run()