Skip to content

Asynchronous listening and processing of multicast messages in PySide6 app #170

@Antoine101

Description

@Antoine101

Hi all,

I am having difficulties integrating asyncio with Pyside for the following use case.
I have read through numerous docs and articles but still struggle to assemble the pieces of the puzzle.
I figured I should ask here directly. Sorry in advance if is not the appropriate channel. I didn't see any Discussions channel.

What I want to acheive:

I have several emitters (up to 30) sending messages independently every few milliseconds (200ms) in multicast.
I have a python PySide app that needs to listen to these incoming messages, process them, and update a map plot accordingly (move shapes, change colors of markers, etc...).
Because I cannot share what I am working on for confidentialy purposes, I have devised a proxy example that is simpler and close enough to my actual need that I can share here.

In this proxy example:

I have an emitter script that sends messages indefinitely on two ports, at a rate that can be modified (here the sleep time is of 1s). This simulates my sensors that emit messages. In this script, messages are sent each time one after the other. To be close to reality I guess we ought to have two separate scripts run in two different consoles. But I think this one can do the trick here. The messages consist in random numbers in this example.
On the receiving side, I want to create an app with PySide that receives those messages, processes them (multiply the numbers by 100) and displays them in two text boxes, each associated with a different port.
enter image description here

I am looking at using an asynchronous approach with asyncio here because I think my problem is mainly I/O-bound. The processing stage is minimal. In my real example it would amount to updating shapes on a satellite view map (leaflet via javascript), maybe doing a few calculations on the received data before that, but nothing too CPU-intensive. I also chose to embed my plot in a PySide app to be able to add more buttons and features later on. Please feel free to indicate any other solution that would be more suitable (multiple threads? multiple processes?).

Anyway, I have tried the following qt doc minimal example but it does not work.

And now I am calling for your help.

Below are the emitter script as well as the code base for the PySide app, without the asynchronous listening and processing stages (I asked Le Chat to generate the full Pyside app but it never works that's why I am giving you only the base code to fill in here):

EMITTER.py

import socket
import time
import struct
import random

def send_multicast_messages(port1, port2, multicast_group='224.1.1.1'):
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    ttl = struct.pack('b', 1)
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)

    try:
        while True:
            # Generate a random value for port1
            value1 = random.randint(1, 100)
            message1 = f"{value1}"
            sock.sendto(message1.encode(), (multicast_group, port1))
            print(f"Sent to port {port1}: {message1}")

            # Generate a random value for port2
            value2 = random.randint(1, 100)
            message2 = f"{value2}"
            sock.sendto(message2.encode(), (multicast_group, port2))
            print(f"Sent to port {port2}: {message2}")

            time.sleep(1)

    except KeyboardInterrupt:
        print("\nExiting the program.")
    finally:
        sock.close()

if __name__ == "__main__":
    port1 = 5000
    port2 = 6000
    send_multicast_messages(port1, port2)

APP.py

import sys
from PySide6.QtWidgets import (
    QApplication, QMainWindow, QVBoxLayout, QTextEdit, QLabel, QWidget
)

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Port Monitor")
        self.setGeometry(100, 100, 400, 300)

        # Create widgets
        self.label1 = QLabel("Port 5000:")
        self.text_edit1 = QTextEdit()
        self.text_edit1.setReadOnly(True)

        self.label2 = QLabel("Port 6000:")
        self.text_edit2 = QTextEdit()
        self.text_edit2.setReadOnly(True)

        # Layout
        layout = QVBoxLayout()
        layout.addWidget(self.label1)
        layout.addWidget(self.text_edit1)
        layout.addWidget(self.label2)
        layout.addWidget(self.text_edit2)

        # Central widget
        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())

Thank you very much in advance for your help.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions