Visualizza post

Questa sezione ti permette di visualizzare tutti i post inviati da questo utente. N.B: puoi vedere solo i post relativi alle aree dove hai l'accesso.


Post - Anakin73

Pagine: [1]
1
PyQT / Re:Condividere dizionari tra due processi
« il: Febbraio 03, 2021, 09:09 »
Buongiorno a tutti.
Finalmente ho risolto il problema, lascio qui la soluzione sperando possa essere utile a qualcun altro della Community.  ;)
La soluzione l'ho trovata con Ray https://ray.io/, un pacchetto che offre, con pochi comandi, la gestione dei subprocessi in modo eccellente.
Oltre ad importarlo con il classico import ray, bisogna inserire all'inizio del codice il comando ray.init() e inserire il decoratore @ray.remote prima della classe o della funzione che si vuole "mandare" nel sotto processo.
La cosa più complessa è stata, per me, gestire il flusso dei dati di ritorno perchè nelle istruzioni non era ben chiaro il meccanismo, mi spiego meglio:
se ho due sotto processi di durata differente la funzione ray.get(miaFunzione) preleva i dati aspettando che tutti i sottoprocessi siano completati, per questo va utilizzata la funzione ray.wait(miaFunzione) che restituisce due liste (qui sono impazzito fin quando non ho trovato questo articolo https://medium.com/distributed-computing-with-ray/ray-tips-and-tricks-part-i-ray-wait-9ed7a0b9836d), la prima contiene lo/gli oggetto/i di tipo Actors o Functions risolti, la seconda quelli non ancora pronti. Si deve eseguire la ray.get() solo sulla prima lista. Un altro consiglio che mi sento di dare è: se avete necessità, come ne mio caso, di eseguire questi processi all'infinito, bisogna rimuovere dalla lista delle funzioni quelle risolte perchè non vengono rimosse in automatico (questo mi è sembrato strano, ma non sono riuscito a fare di meglio che toglierle manualmente).
Inserisco qui sotto il mio prog. di prova, ci sono delle classi modificate da me quindi non vi funzionerà però spero che il listato possa aiutare nella comprensione. Ah dimenticavo, questi sono i tempi di esecuzione delle letture:
Ready length, values:  1 ('/dev/ttyUSB1', [[0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
Not Ready length: 1
duration com= 0.017377614974975586
Ready length, values:  1 ('/dev/ttyUSB0', [[218.3000030517578], [0.06800000369548798], [6.300000190734863], [6.4808149337768555], [0.0], [0.9767923951148987], [50.0], [6.712806701660156], [1.7009999752044678]])
Not Ready length: 1
duration com= 0.0005311965942382812
comunicazione0 = {"port":"/dev/ttyUSB1","baudrate":115200,"parity":"N","bytesize":8,"stopbits":1,"method":"rtu","timeout":0.005}
comunicazione1 = {"port":"/dev/ttyUSB0","baudrate":9600,"parity":"N","bytesize":8,"stopbits":1,"method":"rtu","timeout":0.5}

data0 = [{"unit":1,"funz":0x01,"address":0x0000,"count":0x08,"tipo":"OU"},
         {"unit":2,"funz":0x02,"address":0x0000,"count":0x10,"tipo":"DI"},
        #  {"unit":3,"funz":0x03,"address":0x0BB8,"count":0x04,"tipo":"AO","timeout":0.05},
         {"unit":4,"funz":0x02,"address":0x0000,"count":0x10,"tipo":"DI"},
         {"unit":5,"funz":0x02,"address":0x0000,"count":0x10,"tipo":"DI"},
         {"unit":6,"funz":0x02,"address":0x0000,"count":0x10,"tipo":"OU"}]

data1 = [{"unit":1,"funz":0x04,"count":0x02,"address":  0,"typeVal":"float"},
         {"unit":1,"funz":0x04,"count":0x02,"address":  6,"typeVal":"float"},
         {"unit":1,"funz":0x04,"count":0x02,"address": 12,"typeVal":"float"},
         {"unit":1,"funz":0x04,"count":0x02,"address": 18,"typeVal":"float"},
         {"unit":1,"funz":0x04,"count":0x02,"address": 24,"typeVal":"float"},   
         {"unit":1,"funz":0x04,"count":0x02,"address": 30,"typeVal":"float"},
         {"unit":1,"funz":0x04,"count":0x02,"address": 70,"typeVal":"float"},
         {"unit":1,"funz":0x04,"count":0x02,"address": 86,"typeVal":"float"},
         {"unit":1,"funz":0x04,"count":0x02,"address":342,"typeVal":"float"}]

import MJTool
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import ray
import time

class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setFixedSize(400,400)
        self.mainLayout = QVBoxLayout(self)
        self.layout0 = QHBoxLayout()
        self.layout1 = QVBoxLayout()

        self.lbl1 = QLabel()
        self.lbl2 = QLabel()
        self.btnCnt = QPushButton('Cnt1')
        self.btnCnt.setCheckable(True)
 
        self.layout0.addWidget(self.btnCnt)

        self.layout1.addWidget(self.lbl1)
        self.layout1.addWidget(self.lbl2)
       
        self.mainLayout.addLayout(self.layout0)
        self.mainLayout.addLayout(self.layout1)     

    def setText(self,val1=None,val2=None):
        if val1 != None:
            self.lbl1.setText(str(val1))
        if val2 !=None:
            self.lbl2.setText(str(val2))

    def closeEvent(self, event):
        self.close()
        print("main process finished")


ray.init()
@ray.remote
class Com0():
    def __init__(self,com,dati):
        self.com  = com
        self.dati = dati
        self.client = MJTool.MJModbus_tk()  #Pacchetto MOdbus_tk modificato (esegue anche la funzione 17)
        self.val = []

    def comunicaCOM(self):
        self.val.clear()
        for dato in self.dati:
            self.client.comunica(dato)
            self.val.append(self.client.valore)   
        return self.client.client._serial.port, self.val  #aggiungo il valore della porta seriale per riconoscere la funzione di ritorno

    def com_avvio(self):
        self.client.connetti(self.com)



f=[]

if __name__ == "__main__":
    import sys
   
    app = QApplication(sys.argv)

    main = MainWindow()

    com0 = Com0.remote(comunicazione0,data0)
    com0.com_avvio.remote()

    com1 = Com0.remote(comunicazione1,data1)
    com1.com_avvio.remote()

    timer = QTimer(main)
    timer.start()

    def setTimer():
        global f
        if main.btnCnt.isChecked():
            start = time.time()

            if len(f) == 0: #inizializzo la lista funzioni
                f.append(com1.comunicaCOM.remote())
                f.append(com0.comunicaCOM.remote())

            ready, not_ready = ray.wait(f)
            valore = ray.get(ready)[0]
            print('Ready length, valori in Ready: ', len(ready), valore)
            print('Not Ready length:', len(not_ready))
            f.pop(f.index(ready[0]))   

            if valore[0] == comunicazione1["port"]:
                main.setText(val2=valore)
                f.append(com1.comunicaCOM.remote())

            elif valore[0] == comunicazione0["port"]:
                main.setText(valore)   
                f.append(com0.comunicaCOM.remote())
               
            print("duration com=", time.time() - start)
       
           
    timer.timeout.connect(setTimer)

    main.show()

    sys.exit(app.exec_())

2
Quello che manca è un QLayout dove mettere e togliere gli oggetti che desideri.
Puoi immaginare il QWidget come un luogo generico "astratto",i QLayout dei contenitori, i QFrame come dei fogli e tutti gli altri oggetti  qualcosa da attaccare sui fogli o mettere nei contenitori.
Comunque la risposta che cerchi è utilizzare self.frameIntro.setParent(None) per togliere il QFrame dal central_Widget e self.frameDati.setParent(self.central_Widget) per mettere quello nuovo, come sembrerebbe tu abbia fatto ma, pur non conoscendo la classe FrameDatiUfficio, potrei ipotizzare che quel self non viene incanalato correttamente.
Dovrebbe essere una classe tipo questa, per dire all'oggetto self.frameDati di legarsi con central_Widget
class FrameDatiUfficio(QtWidgets.QFrame):
    def __init__(self,parent):
        super().__init__(parent)

Ma la soluzione più "elegante", a mio avviso, è utilizzare: self.mioLayout = QtWidgets.QLayout(self) - ci sono le varianti HBOX, VBOX e GRID che si adattano meglio alle tue esigenze - per creare il contenitore con tutte le caratteristiche di expanding, alignment ecc...
poi  self.mioLayout.clear() per svuotare il contenuto e self.mioLayout.addWidget(self.frameDati)

3
PyQT / Re:Valore preimpostato in ComboBox
« il: Gennaio 30, 2021, 13:37 »
Ciao paparucino,
Se ho ben capito il tuo problema sta nel fatto che vorresti far apparire nel combo box, appena si avvia il programma, la data attuale.

qui ho scritto un pezzo di codice per vedere se ho capito cosa intendi.
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from datetime import datetime

class MyComboBox(QWidget):
    def __init__(self):
        super().__init__()
        self.Extract_Year_select = QComboBox(self)
        self.Extract_Year_select.setGeometry(QRect(380, 140, 80, 20))
        self.Extract_Year_select.setObjectName("Extract_Year_select")
        self.Extract_Year_select.addItems(['2017', '2018', '2019', '2020', '2021', '2022', '2023', '2024'])
        oggi = datetime.now()
        self.this_year = oggi.strftime("%Y")
        self.Extract_Year_select.setCurrentText(self.this_year)
        self.Extract_Year_select.currentTextChanged.connect(self.AnnoSelected_func)

    def AnnoSelected_func(self,anno):
        print(anno)

if __name__ == "__main__":
    valore = 0
    app = QApplication(sys.argv)
    Main = MyComboBox()
    x = int((app.desktop().screenGeometry().width()-Main.size().width())/2)
    y = int((app.desktop().screenGeometry().height()-Main.size().height())/2)
    Main.move(x,y)
    Main.show()

    sys.exit(app.exec_())

E' questo che intendevi?

4
PyQT / Re:Condividere dizionari tra due processi
« il: Gennaio 30, 2021, 12:59 »
Se può aiutare vi mando la stampa dei due oggetti (COM0 e COM1) che come si può vedere sembrano condividere la stessa area di memoria (?)
E' possibile?
<__main__.ComunicationRS485 object at 0x7f1d429829d0> COM1
<__main__.ComunicationRS485 object at 0x7f1d429829d0> COM0

Questi due oggetti sono stati creati in questo modo:
def process1():
    Thread1 =  QApplication([])
    COM1 = ComunicationRS485('COM1')
    print(COM1,COM1.objectName())
    COM1.show()
    sys.exit(Thread1.exec_())


def process0():
    Thread0 = QApplication([])
    COM0 = ComunicationRS485('COM0')
    print(COM0,COM0.objectName())
    COM0.show()
    sys.exit(Thread0.exec_())


if __name__ == "__main__":

    processo0 = Process(target=process0)
    processo1= Process(target=process1)

    processo0.start()
    processo1.start()

5
PyQT / [RISOLTO]Condividere dizionari tra due processi
« il: Gennaio 29, 2021, 19:51 »
Buonasera a tutti,
volevo sottoporvi un problema che mi sta assillando da una settimana.
Sto realizzando una domotica per la mia casa, ho acquistato un pc all-in-one sul quale ho installato Ubuntu 20.04 il pc ha un processore i7 quadcore 16G RAM.
Ho realizzato il pannello di controllo e programmazione della domotica utilizzando Python3.8 e come libreria GUI PyQt5
Il programma realizzato ha anche la funzione di chiamare, con protocollo Modbus utilizzando la libreria Modbus_tk, dei dispositivi suddivisi su due linee RS485 native del pc. Una linea ha le seguenti caratteristiche 115200 ,N,8,1. L'altra 9600,N,8,1.
Su quella più veloce leggo e scrivo i dispositivi di I/O sull'altra i "servizi" (un analizzatore di rete, l'inverter del FV  e la pompa di calore).
Tutto funziona meravigliosamente ma, ecco l'assillo, eseguendo le letture delle due linee rs485 in sequenza, risulta che la linea più lenta infici le prestazioni dell'altra e cosa peggiore, quando (e purtroppo capita sovente) l'inverter FV è in spegnimento o in accensione e non comunica, il timeout di "non risposta" blocca il processo di lettura di entrambe le linee per 500 mS sembra una banalità, ma vi assicuro che è veramente noiso il ritardo di accensione o quello di lettura dei pulsanti.
Ho cercato di risolvere con QRunnable o con QThread, la cosa migliora in caso di "non risposta" ma non risolve il problema del conflitto (se così si può definire) tra le due linee. L'unica soluzione funzionante che ho trovato è stata quella di creare un thread contenente  due QApplication contenenti i "loop" della lettura continua della linea a 115200 e di quella a 9600 e una QApplication contenete il programma principale. Il problema che avrete già intuito e che non riesco a "prendere" i dati letti ne ad inviare dati da scrivere, pertanto il mio assillo sta nel poter condividere tra i due "loop" e il programma principale il dizionario contenente le informazioni di I/O.
Avete dei suggerimenti?
Grazie mille!

6
PyQT / Re:[RISOLTO]QPushButton
« il: Giugno 25, 2020, 19:01 »
Lascio un commento per chi si dovesse trovare  in futuro nello stesso mio problema.
Ho risolto cercando nella classe Padre QAbstractButton, da qui QpushButton eredita il segnale pressed e released o collegato i due segnali a due definizioni in questo modo:
    self.In.pressed.connect(self.upClick) #In è il QpushButton
    self.In.released.connect(self.dwClick)
    def upClick(self):
        self.In.setChecked(True)

    def dwClick(self):
        self.In.setChecked(False)
 

7
PyQT / [RISOLTO]QPushButton
« il: Giugno 25, 2020, 16:53 »
Buongiorno a tutti,
ho cercato in rete e sulla documentazione ufficiale ma non ho trovato (o forse non ho capito) come rendere il QPushButton un pulsante momentaneo ovvero attivo solo durante la pressione o click prolungato.
Qualcuno può aiutarmi?
Grazie

8
RicPol ti devo una birra!!  :) :party:
Con Qtimer ho risolto e semplificato lo script!!
Grazie infinite!!

9
Altre tematiche / Re:Comunicazione RS485-protocollo ModBus
« il: Giugno 23, 2020, 15:23 »
Grazie nuzzopippo.
Ora controllo i due oggetti che mi hai suggerito.
In merito all'ultima domanda la risposta è sì e pertanto convalida la tua tesi.
Vi tengo aggiornati.
Poi se arrivano altri suggerimenti... :)

10
Buongiorno a tutti.
Utilizzando la libreria pymodbus ho creato uno script che legge un dispositivo di Input a 16 ingressi e fino a qui tutto liscio. Volendo interrogare continuamente il dispositivo l'unica soluzione che ho trovato è aggiungere un ciclo while a:

com = {"port":"COM5","baudrate":9600,"parity":'N',"bytesize":8,"stopbits":1,"method":"rtu","timeout":1} #dizionario contenente le caratteristiche di comunicazione
dati = {"nodo":1,"funzione":2,"indirizzo":0,"punti":16,"valore":[],"endianness":"L"} #dizionario contente i dati Modbus da inviare
IN = ComandiModBus(com) # istanziamento dell'oggetto IN della classe ComandiModbus figlia della classe pymodbus.client.sync
while True: # ciclo while aggiunto
      listaBool = IN.read(dati) #carico sulla lista "listaBool" i valori letti

Il problema è che il ciclo while è bloccante e vorrei poter eseguire altre funzioni durante queste "chiamate".
Esiste un metodo per eseguire delle funzioni in background?
Ho provato i thread ma non riesco a farli funzionare con pyqt5 (finestra nella quale vorrei rappresentare lo stato degli ingressi del dispositivo di Input) in particolare appena creo l'oggetto QApplication(sys.argv) lo script crasha :(
Grazie
     

11
Benvenuto e regolamento / Buongiorno a tutti!!
« il: Giugno 23, 2020, 12:34 »
Buongiorno, sono un nuovo iscritto a questo forum su Python.
Ho seguito alcuni corsi e tutorial ma ho ancora molto da imparare... sono qui per questo  :)
Programmo PLC con lo standard IEC 61131 e ho realizzato alcune applicazioni in Python e VisualBasic... che dire... è un mondo che mi affascina!
Sono molto contento di far parte di questa community (è da un po' che vi seguo da visitatore), vi auguro una bellissima giornata e grazie di avermi accettato!!

Pagine: [1]