Sun, 18 Jul 2021 18:30:15 +0200
Added the MQTT protocol version to the list of connection parameters.
diff -r 06d1cba236eb -r 21f9c010dc42 MqttMonitor/MqttClient.py --- a/MqttMonitor/MqttClient.py Mon Jun 28 17:44:07 2021 +0200 +++ b/MqttMonitor/MqttClient.py Sun Jul 18 18:30:15 2021 +0200 @@ -7,6 +7,8 @@ Module implementing a PyQt wrapper around the paho MQTT client. """ +import enum + from PyQt6.QtCore import ( pyqtSignal, pyqtSlot, QObject, QCoreApplication, QTimer ) @@ -16,6 +18,15 @@ from Utilities.crypto import pwConvert +class MqttProtocols(enum.IntEnum): + """ + Class defining the supported MQTT protocol versions. + """ + MQTTv31 = mqtt.MQTTv31 + MQTTv311 = mqtt.MQTTv311 + MQTTv5 = mqtt.MQTTv5 + + class MqttClient(QObject): """ Class implementing a PyQt wrapper around the paho MQTT client. @@ -73,7 +84,7 @@ @param userdata user data @type any @param protocol version of the MQTT protocol to use - @type int, one of mqtt.MQTTv3, mqtt.MQTTv311 or mqtt.MQTTv5 + @type int, one of mqtt.MQTTv31, mqtt.MQTTv311 or mqtt.MQTTv5 @param transport transport to be used @type str, one of "tcp" or "websockets" @param parent reference to the parent object @@ -91,10 +102,13 @@ self.onConnect.connect(self.__connectTimeoutTimer.stop) - # TODO: MQTTv5: set clean_session to None and remember cleanSession + self.__cleanSession = cleanSession + if protocol == MqttProtocols.MQTTv5: + cleanSession = None + self.__mqttClient = mqtt.Client( - client_id=clientId, clean_session=cleanSession, userdata=None, - protocol=mqtt.MQTTv311, transport="tcp") + client_id=clientId, clean_session=cleanSession, userdata=userdata, + protocol=int(protocol), transport=transport) self.__initCallbacks() @@ -371,20 +385,22 @@ self.connectToServer(host, port=port, keepalive=keepalive, bindAddress=bindAddress) - def defaultConnectionOptions(self): + @classmethod + def defaultConnectionOptions(cls): """ - Public method to get a connection options dictionary with default + Class method to get a connection options dictionary with default values. @return dictionary containing the default connection options. It has - the keys "ClientId", "Keepalive", "CleanSession", "Username", - "Password", "WillTopic", "WillMessage", "WillQos", "WillRetain", - "TlsEnable", "TlsCaCert", "TlsClientCert", "TlsClientKey", - "ConnectionTimeout". + the keys "ClientId", "Protocol", "ConnectionTimeout", "Keepalive", + "CleanSession", "Username", "Password", "WillTopic", "WillMessage", + "WillQos", "WillRetain", "TlsEnable", "TlsCaCert", "TlsClientCert", + "TlsClientKey". @rtype dict """ return { "ClientId": "ERIC7_MQTT_MONITOR_CLIENT", + "Protocol": MqttProtocols.MQTTv311, "ConnectionTimeout": MqttClient.DefaultConnectTimeout, "Keepalive": 60, "CleanSession": True,
diff -r 06d1cba236eb -r 21f9c010dc42 MqttMonitor/MqttConnectionOptionsDialog.py --- a/MqttMonitor/MqttConnectionOptionsDialog.py Mon Jun 28 17:44:07 2021 +0200 +++ b/MqttMonitor/MqttConnectionOptionsDialog.py Sun Jul 18 18:30:15 2021 +0200 @@ -15,6 +15,8 @@ from .Ui_MqttConnectionOptionsDialog import Ui_MqttConnectionOptionsDialog +from .MqttClient import MqttClient, MqttProtocols + from Utilities.crypto import pwConvert @@ -22,17 +24,15 @@ """ Class implementing a dialog to enter MQTT connection options. """ - def __init__(self, client, options=None, parent=None): + def __init__(self, options=None, parent=None): """ Constructor - @param client reference to the MQTT client object - @type MqttClient @param options dictionary containing the connection options to populate the dialog with. It must have the keys "ClientId", - "Keepalive", "CleanSession", "Username", "Password", "WillTopic", - "WillMessage", "WillQos", "WillRetain", "TlsEnable", "TlsCaCert", - "ConnectionTimeout". + "Protocol", "ConnectionTimeout", "Keepalive", "CleanSession", + "Username", "Password", "WillTopic", "WillMessage", "WillQos", + "WillRetain", "TlsEnable", "TlsCaCert". @type dict @param parent reference to the parent widget @type QWidget @@ -40,8 +40,6 @@ super().__init__(parent) self.setupUi(self) - self.__client = client - self.tlsCertsFilePicker.setMode(EricPathPickerModes.OPEN_FILE_MODE) self.tlsCertsFilePicker.setFilters( self.tr("Certificate Files (*.crt *.pem);;All Files (*)")) @@ -106,10 +104,16 @@ @type dict """ if options is None: - options = self.__client.defaultConnectionOptions() + options = MqttClient.defaultConnectionOptions() # general self.clientIdEdit.setText(options["ClientId"]) + self.mqttv31Button.setChecked( + options["Protocol"] == MqttProtocols.MQTTv31) + self.mqttv311Button.setChecked( + options["Protocol"] == MqttProtocols.MQTTv311) + self.mqttv5Button.setChecked( + options["Protocol"] == MqttProtocols.MQTTv5) self.connectionTimeoutSpinBox.setValue(options["ConnectionTimeout"]) self.keepaliveSpinBox.setValue(options["Keepalive"]) self.cleanSessionCheckBox.setChecked(options["CleanSession"]) @@ -133,13 +137,23 @@ Public method get the entered connection options. @return dictionary containing the connection options. It has the keys - "ClientId", "Keepalive", "CleanSession", "Username", "Password", - "WillTopic", "WillMessage", "WillQos", "WillRetain", "TlsEnable", - "TlsCaCert", "ConnectionTimeout". + "ClientId", "Protocol", "ConnectionTimeout", "Keepalive", + "CleanSession", "Username", "Password", "WillTopic", "WillMessage", + "WillQos", "WillRetain", "TlsEnable", "TlsCaCert". @rtype dict """ + if self.mqttv31Button.isChecked(): + protocol = MqttProtocols.MQTTv31 + elif self.mqttv311Button.isChecked(): + protocol = MqttProtocols.MQTTv311 + elif self.mqttv5Button.isChecked(): + protocol = MqttProtocols.MQTTv5 + else: + protocol = MqttProtocols.MQTTv311 + return { "ClientId": self.clientIdEdit.text(), + "Protocol": protocol, "ConnectionTimeout": self.connectionTimeoutSpinBox.value(), "Keepalive": self.keepaliveSpinBox.value(), "CleanSession": self.cleanSessionCheckBox.isChecked(),
diff -r 06d1cba236eb -r 21f9c010dc42 MqttMonitor/MqttConnectionOptionsDialog.ui --- a/MqttMonitor/MqttConnectionOptionsDialog.ui Mon Jun 28 17:44:07 2021 +0200 +++ b/MqttMonitor/MqttConnectionOptionsDialog.ui Sun Jul 18 18:30:15 2021 +0200 @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>550</width> - <height>650</height> + <height>675</height> </rect> </property> <property name="windowTitle"> @@ -16,50 +16,96 @@ <property name="sizeGripEnabled"> <bool>true</bool> </property> - <layout class="QVBoxLayout" name="verticalLayout"> + <layout class="QVBoxLayout" name="verticalLayout_2"> <item> <widget class="QGroupBox" name="groupBox"> <property name="title"> <string>General</string> </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Client ID:</string> - </property> - </widget> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Client ID:</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="clientIdEdit"> + <property name="toolTip"> + <string>Enter the ID string for this client</string> + </property> + <property name="clearButtonEnabled"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="generateIdButton"> + <property name="toolTip"> + <string>Press to generate a client ID</string> + </property> + <property name="text"> + <string>Generate</string> + </property> + </widget> + </item> + </layout> </item> - <item row="0" column="1"> - <widget class="QLineEdit" name="clientIdEdit"> - <property name="toolTip"> - <string>Enter the ID string for this client</string> + <item> + <widget class="QGroupBox" name="groupBox_5"> + <property name="title"> + <string>MQTT Protocol</string> </property> - <property name="clearButtonEnabled"> - <bool>true</bool> - </property> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QRadioButton" name="mqttv31Button"> + <property name="toolTip"> + <string>Select to use the MQTT 3.1 protocol</string> + </property> + <property name="text"> + <string>v 3.1</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="mqttv311Button"> + <property name="toolTip"> + <string>Select to use the MQTT 3.1.1 protocol</string> + </property> + <property name="text"> + <string>v 3.1.1</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="mqttv5Button"> + <property name="toolTip"> + <string>Select to use the MQTT 5.0 protocol</string> + </property> + <property name="text"> + <string>v 5.0</string> + </property> + </widget> + </item> + </layout> </widget> </item> - <item row="0" column="2"> - <widget class="QPushButton" name="generateIdButton"> - <property name="toolTip"> - <string>Press to generate a client ID</string> - </property> - <property name="text"> - <string>Generate</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_6"> - <property name="text"> - <string>Connection Timeout:</string> - </property> - </widget> - </item> - <item row="1" column="1" colspan="2"> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <item> + <item> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label_6"> + <property name="text"> + <string>Connection Timeout:</string> + </property> + </widget> + </item> + <item row="0" column="1"> <widget class="QSpinBox" name="connectionTimeoutSpinBox"> <property name="toolTip"> <string>Enter the connection timeout in seconds</string> @@ -81,7 +127,7 @@ </property> </widget> </item> - <item> + <item row="0" column="2"> <spacer name="horizontalSpacer_2"> <property name="orientation"> <enum>Qt::Horizontal</enum> @@ -94,18 +140,14 @@ </property> </spacer> </item> - </layout> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>Keep Alive Interval:</string> - </property> - </widget> - </item> - <item row="2" column="1" colspan="2"> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Keep Alive Interval:</string> + </property> + </widget> + </item> + <item row="1" column="1"> <widget class="QSpinBox" name="keepaliveSpinBox"> <property name="toolTip"> <string>Enter the keep alive interval in seconds</string> @@ -127,7 +169,7 @@ </property> </widget> </item> - <item> + <item row="1" column="2"> <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> @@ -142,7 +184,7 @@ </item> </layout> </item> - <item row="3" column="0" colspan="3"> + <item> <widget class="QCheckBox" name="cleanSessionCheckBox"> <property name="toolTip"> <string>Select to start with a clean session</string> @@ -331,15 +373,18 @@ <tabstops> <tabstop>clientIdEdit</tabstop> <tabstop>generateIdButton</tabstop> + <tabstop>mqttv31Button</tabstop> + <tabstop>mqttv311Button</tabstop> + <tabstop>mqttv5Button</tabstop> <tabstop>connectionTimeoutSpinBox</tabstop> <tabstop>keepaliveSpinBox</tabstop> <tabstop>cleanSessionCheckBox</tabstop> <tabstop>usernameEdit</tabstop> <tabstop>passwordEdit</tabstop> <tabstop>willTopicEdit</tabstop> - <tabstop>willMessageEdit</tabstop> <tabstop>willQosSpinBox</tabstop> <tabstop>willRetainCheckBox</tabstop> + <tabstop>willMessageEdit</tabstop> <tabstop>tlsEnableCheckBox</tabstop> <tabstop>tlsCertsFilePicker</tabstop> </tabstops>
diff -r 06d1cba236eb -r 21f9c010dc42 MqttMonitor/MqttConnectionProfilesDialog.py --- a/MqttMonitor/MqttConnectionProfilesDialog.py Mon Jun 28 17:44:07 2021 +0200 +++ b/MqttMonitor/MqttConnectionProfilesDialog.py Sun Jul 18 18:30:15 2021 +0200 @@ -20,6 +20,8 @@ from .Ui_MqttConnectionProfilesDialog import Ui_MqttConnectionProfilesDialog +from .MqttClient import MqttClient, MqttProtocols + import UI.PixmapCache from Utilities.crypto import pwConvert @@ -28,18 +30,16 @@ """ Class implementing a dialog to edit the MQTT connection profiles. """ - def __init__(self, client, profiles, parent=None): + def __init__(self, profiles, parent=None): """ Constructor - @param client reference to the MQTT client object - @type MqttClient @param profiles dictionary containing dictionaries containing the connection parameters. Each entry must have the keys - "BrokerAddress", "BrokerPort", "ClientId", - "Keepalive", "CleanSession", "Username", "Password", "WillTopic", - "WillMessage", "WillQos", "WillRetain", "TlsEnable", "TlsCaCert", - "TlsClientCert", "TlsClientKey", "ConnectionTimeout". + "BrokerAddress", "BrokerPort", "ClientId", "Protocol", + "ConnectionTimeout", "Keepalive", "CleanSession", "Username", + "Password", "WillTopic", "WillMessage", "WillQos", "WillRetain", + "TlsEnable", "TlsCaCert", "TlsClientCert", "TlsClientKey". @type dict @param parent reference to the parent widget @type QWidget @@ -47,8 +47,6 @@ super().__init__(parent) self.setupUi(self) - self.__client = client - self.__profiles = collections.defaultdict(self.__defaultProfile) self.__profiles.update(profiles) self.__profilesChanged = False @@ -239,10 +237,10 @@ @return dictionary containing dictionaries containing the defined connection profiles. Each entry have the keys "BrokerAddress", - "BrokerPort", "ClientId", "Keepalive", "CleanSession", "Username", - "Password", "WillTopic", "WillMessage", "WillQos", "WillRetain", - "TlsEnable", "TlsCaCert", "TlsClientCert", "TlsClientKey", - "ConnectionTimeout". + "BrokerPort", "ClientId", "Protocol", "ConnectionTimeout", + "Keepalive", "CleanSession", "Username", "Password", "WillTopic", + "WillMessage", "WillQos", "WillRetain", "TlsEnable", "TlsCaCert", + "TlsClientCert", "TlsClientKey". @rtype dict """ profilesDict = {} @@ -256,11 +254,21 @@ @return name of the applied profile @rtype str """ + if self.mqttv31Button.isChecked(): + protocol = MqttProtocols.MQTTv31 + elif self.mqttv311Button.isChecked(): + protocol = MqttProtocols.MQTTv311 + elif self.mqttv5Button.isChecked(): + protocol = MqttProtocols.MQTTv5 + else: + protocol = MqttProtocols.MQTTv311 + profileName = self.profileEdit.text() - profile = { + connectionProfile = { "BrokerAddress": self.brokerAddressEdit.text(), "BrokerPort": self.brokerPortSpinBox.value(), "ClientId": self.clientIdEdit.text(), + "Protocol": protocol, "ConnectionTimeout": self.connectionTimeoutSpinBox.value(), "Keepalive": self.keepaliveSpinBox.value(), "CleanSession": self.cleanSessionCheckBox.isChecked(), @@ -275,18 +283,18 @@ "TlsClientCert": "", "TlsClientKey": "", } - if profile["TlsEnable"]: + if connectionProfile["TlsEnable"]: if self.tlsCertsFileButton.isChecked(): - profile["TlsCaCert"] = self.tlsCertsFilePicker.text() + connectionProfile["TlsCaCert"] = self.tlsCertsFilePicker.text() elif self.tlsSelfSignedCertsButton.isChecked(): - profile["TlsCaCert"] = ( + connectionProfile["TlsCaCert"] = ( self.tlsSelfSignedCertsFilePicker.text()) - profile["TlsClientCert"] = ( + connectionProfile["TlsClientCert"] = ( self.tlsSelfSignedClientCertFilePicker.text()) - profile["TlsClientKey"] = ( + connectionProfile["TlsClientKey"] = ( self.tlsSelfSignedClientKeyFilePicker.text()) - self.__profiles[profileName] = profile + self.__profiles[profileName] = connectionProfile self.__profilesChanged = True return profileName @@ -298,7 +306,7 @@ @return default dictionary entry @rtype dict """ - defaultProfile = self.__client.defaultConnectionOptions() + defaultProfile = MqttClient.defaultConnectionOptions() defaultProfile["BrokerAddress"] = "" if defaultProfile["TlsEnable"]: defaultProfile["BrokerPort"] = 8883 @@ -338,36 +346,48 @@ @param profileName name of the profile to get data from @type str """ - profile = self.__defaultProfile() + connectionProfile = self.__defaultProfile() if profileName: - profile.update(self.__profiles[profileName]) + connectionProfile.update(self.__profiles[profileName]) self.__populatingProfile = True if profileName is not None: self.profileEdit.setText(profileName) - self.brokerAddressEdit.setText(profile["BrokerAddress"]) - self.brokerPortSpinBox.setValue(profile["BrokerPort"]) - self.clientIdEdit.setText(profile["ClientId"]) - self.connectionTimeoutSpinBox.setValue(profile["ConnectionTimeout"]) - self.keepaliveSpinBox.setValue(profile["Keepalive"]) - self.cleanSessionCheckBox.setChecked(profile["CleanSession"]) - self.usernameEdit.setText(profile["Username"]) - self.passwordEdit.setText(pwConvert(profile["Password"], encode=False)) - self.willTopicEdit.setText(profile["WillTopic"]) - self.willMessageEdit.setPlainText(profile["WillMessage"]) - self.willQosSpinBox.setValue(profile["WillQos"]) - self.willRetainCheckBox.setChecked(profile["WillRetain"]) - self.tlsGroupBox.setChecked(profile["TlsEnable"]) - if profile["TlsCaCert"] and profile["TlsClientCert"]: + self.brokerAddressEdit.setText(connectionProfile["BrokerAddress"]) + self.brokerPortSpinBox.setValue(connectionProfile["BrokerPort"]) + self.clientIdEdit.setText(connectionProfile["ClientId"]) + self.mqttv31Button.setChecked( + connectionProfile["Protocol"] == MqttProtocols.MQTTv31) + self.mqttv311Button.setChecked( + connectionProfile["Protocol"] == MqttProtocols.MQTTv311) + self.mqttv5Button.setChecked( + connectionProfile["Protocol"] == MqttProtocols.MQTTv5) + self.connectionTimeoutSpinBox.setValue( + connectionProfile["ConnectionTimeout"]) + self.keepaliveSpinBox.setValue(connectionProfile["Keepalive"]) + self.cleanSessionCheckBox.setChecked(connectionProfile["CleanSession"]) + self.usernameEdit.setText(connectionProfile["Username"]) + self.passwordEdit.setText( + pwConvert(connectionProfile["Password"], encode=False)) + self.willTopicEdit.setText(connectionProfile["WillTopic"]) + self.willMessageEdit.setPlainText(connectionProfile["WillMessage"]) + self.willQosSpinBox.setValue(connectionProfile["WillQos"]) + self.willRetainCheckBox.setChecked(connectionProfile["WillRetain"]) + self.tlsGroupBox.setChecked(connectionProfile["TlsEnable"]) + if ( + connectionProfile["TlsCaCert"] and + connectionProfile["TlsClientCert"] + ): self.tlsSelfSignedCertsButton.setChecked(True) - self.tlsSelfSignedCertsFilePicker.setText(profile["TlsCaCert"]) + self.tlsSelfSignedCertsFilePicker.setText( + connectionProfile["TlsCaCert"]) self.tlsSelfSignedClientCertFilePicker.setText( - profile["TlsClientCert"]) + connectionProfile["TlsClientCert"]) self.tlsSelfSignedClientKeyFilePicker.setText( - profile["TlsClientKey"]) - elif profile["TlsCaCert"]: + connectionProfile["TlsClientKey"]) + elif connectionProfile["TlsCaCert"]: self.tlsCertsFileButton.setChecked(True) - self.tlsCertsFilePicker.setText(profile["TlsCaCert"]) + self.tlsCertsFilePicker.setText(connectionProfile["TlsCaCert"]) else: self.tlsDefaultCertsButton.setChecked(True) self.__populatingProfile = False @@ -385,6 +405,7 @@ self.brokerAddressEdit.setText("") self.brokerPortSpinBox.setValue(1883) self.clientIdEdit.setText("") + self.mqttv311Button.setChecked(True) self.keepaliveSpinBox.setValue(60) self.cleanSessionCheckBox.setChecked(True) self.usernameEdit.setText("") @@ -436,40 +457,56 @@ return False elif profileName in self.__profiles: - profile = self.__defaultProfile() - profile.update(self.__profiles[profileName]) + if self.mqttv31Button.isChecked(): + protocol = MqttProtocols.MQTTv31 + elif self.mqttv311Button.isChecked(): + protocol = MqttProtocols.MQTTv311 + elif self.mqttv5Button.isChecked(): + protocol = MqttProtocols.MQTTv5 + else: + protocol = MqttProtocols.MQTTv311 + + connectionProfile = self.__defaultProfile() + connectionProfile.update(self.__profiles[profileName]) changed = ( - self.brokerAddressEdit.text() != profile["BrokerAddress"] or - self.brokerPortSpinBox.value() != profile["BrokerPort"] or - self.clientIdEdit.text() != profile["ClientId"] or + self.brokerAddressEdit.text() != + connectionProfile["BrokerAddress"] or + self.brokerPortSpinBox.value() != + connectionProfile["BrokerPort"] or + self.clientIdEdit.text() != connectionProfile["ClientId"] or + protocol != connectionProfile["Protocol"] or self.connectionTimeoutSpinBox.value() != - profile["ConnectionTimeout"] or - self.keepaliveSpinBox.value() != profile["Keepalive"] or + connectionProfile["ConnectionTimeout"] or + self.keepaliveSpinBox.value() != + connectionProfile["Keepalive"] or self.cleanSessionCheckBox.isChecked() != - profile["CleanSession"] or - self.usernameEdit.text() != profile["Username"] or + connectionProfile["CleanSession"] or + self.usernameEdit.text() != connectionProfile["Username"] or self.passwordEdit.text() != - pwConvert(profile["Password"], encode=False) or - self.willTopicEdit.text() != profile["WillTopic"] or - self.willMessageEdit.toPlainText() != profile["WillMessage"] or - self.willQosSpinBox.value() != profile["WillQos"] or - self.willRetainCheckBox.isChecked() != profile["WillRetain"] or - self.tlsGroupBox.isChecked() != profile["TlsEnable"] + pwConvert(connectionProfile["Password"], encode=False) or + self.willTopicEdit.text() != connectionProfile["WillTopic"] or + self.willMessageEdit.toPlainText() != + connectionProfile["WillMessage"] or + self.willQosSpinBox.value() != connectionProfile["WillQos"] or + self.willRetainCheckBox.isChecked() != + connectionProfile["WillRetain"] or + self.tlsGroupBox.isChecked() != connectionProfile["TlsEnable"] ) # check TLS stuff only, if not yet changed if not changed: if self.tlsCertsFileButton.isChecked(): changed |= ( - self.tlsCertsFilePicker.text() != profile["TlsCaCert"] + self.tlsCertsFilePicker.text() != + connectionProfile["TlsCaCert"] ) elif self.tlsSelfSignedCertsButton.isChecked(): changed |= ( self.tlsSelfSignedCertsFilePicker.text() != - profile["TlsCaCert"] or + connectionProfile["TlsCaCert"] or self.tlsSelfSignedClientCertFilePicker.text() != - profile["TlsClientCert"] or + connectionProfile["TlsClientCert"] or self.tlsSelfSignedClientKeyFilePicker.text() != - profile["TlsClientKey"] + connectionProfile["TlsClientKey"] ) return changed
diff -r 06d1cba236eb -r 21f9c010dc42 MqttMonitor/MqttConnectionProfilesDialog.ui --- a/MqttMonitor/MqttConnectionProfilesDialog.ui Mon Jun 28 17:44:07 2021 +0200 +++ b/MqttMonitor/MqttConnectionProfilesDialog.ui Sun Jul 18 18:30:15 2021 +0200 @@ -224,14 +224,56 @@ <string>General</string> </attribute> <layout class="QGridLayout" name="gridLayout_2"> - <item row="0" column="0"> + <item row="0" column="0" colspan="2"> + <widget class="QGroupBox" name="groupBox_5"> + <property name="title"> + <string>MQTT Protocol</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_7"> + <item> + <widget class="QRadioButton" name="mqttv31Button"> + <property name="toolTip"> + <string>Select to use the MQTT 3.1 protocol</string> + </property> + <property name="text"> + <string>v 3.1</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="mqttv311Button"> + <property name="toolTip"> + <string>Select to use the MQTT 3.1.1 protocol</string> + </property> + <property name="text"> + <string>v 3.1.1</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="mqttv5Button"> + <property name="toolTip"> + <string>Select to use the MQTT 5.0 protocol</string> + </property> + <property name="text"> + <string>v 5.0</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="1" column="0"> <widget class="QLabel" name="label_12"> <property name="text"> <string>Connection Timeout:</string> </property> </widget> </item> - <item row="0" column="1"> + <item row="1" column="1"> <layout class="QHBoxLayout" name="horizontalLayout_5"> <item> <widget class="QSpinBox" name="connectionTimeoutSpinBox"> @@ -270,14 +312,14 @@ </item> </layout> </item> - <item row="1" column="0"> + <item row="2" column="0"> <widget class="QLabel" name="label_5"> <property name="text"> <string>Keep Alive Interval:</string> </property> </widget> </item> - <item row="1" column="1"> + <item row="2" column="1"> <layout class="QHBoxLayout" name="horizontalLayout_4"> <item> <widget class="QSpinBox" name="keepaliveSpinBox"> @@ -316,7 +358,7 @@ </item> </layout> </item> - <item row="2" column="0" colspan="2"> + <item row="3" column="0" colspan="2"> <widget class="QCheckBox" name="cleanSessionCheckBox"> <property name="toolTip"> <string>Select to start with a clean session</string> @@ -326,7 +368,7 @@ </property> </widget> </item> - <item row="3" column="1"> + <item row="4" column="1"> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> @@ -742,6 +784,9 @@ <tabstop>clientIdEdit</tabstop> <tabstop>generateIdButton</tabstop> <tabstop>profileTabWidget</tabstop> + <tabstop>mqttv31Button</tabstop> + <tabstop>mqttv311Button</tabstop> + <tabstop>mqttv5Button</tabstop> <tabstop>connectionTimeoutSpinBox</tabstop> <tabstop>keepaliveSpinBox</tabstop> <tabstop>cleanSessionCheckBox</tabstop> @@ -749,9 +794,9 @@ <tabstop>passwordEdit</tabstop> <tabstop>showPasswordButton</tabstop> <tabstop>willTopicEdit</tabstop> - <tabstop>willMessageEdit</tabstop> <tabstop>willQosSpinBox</tabstop> <tabstop>willRetainCheckBox</tabstop> + <tabstop>willMessageEdit</tabstop> <tabstop>tlsGroupBox</tabstop> <tabstop>tlsDefaultCertsButton</tabstop> <tabstop>tlsCertsFileButton</tabstop>
diff -r 06d1cba236eb -r 21f9c010dc42 MqttMonitor/MqttMonitorWidget.py --- a/MqttMonitor/MqttMonitorWidget.py Mon Jun 28 17:44:07 2021 +0200 +++ b/MqttMonitor/MqttMonitorWidget.py Sun Jul 18 18:30:15 2021 +0200 @@ -22,7 +22,8 @@ from .Ui_MqttMonitorWidget import Ui_MqttMonitorWidget from .MqttClient import ( - MqttClient, mqttConnackMessage, mqttErrorMessage, mqttLogLevelString + MqttClient, MqttProtocols, mqttConnackMessage, mqttErrorMessage, + mqttLogLevelString ) import UI.PixmapCache @@ -184,19 +185,35 @@ self.__statusLoadValues = collections.defaultdict( self.__loadDefaultDictFactory) + + ####################################################################### + ## Slots handling MQTT related signals + ####################################################################### + + def __createClient(self, protocol=MqttProtocols.MQTTv311): + """ + Private method to instantiate a MQTT client for a given protocol. - self.__client = MqttClient() + @param protocol MQTT protocol version to be used (defaults to + MqttProtocols.MQTTv311) + @type MqttProtocols (optional) + @return created and connected MQTT client object + @rtype MqttClient + """ + client = MqttClient(protocol=protocol) # connect the MQTT client signals - self.__client.onConnect.connect(self.__brokerConnected) - self.__client.onDisconnected.connect(self.__brokerDisconnected) - self.__client.onLog.connect(self.__clientLog) - self.__client.onMessage.connect(self.__messageReceived) - self.__client.onPublish.connect(self.__messagePublished) - self.__client.onSubscribe.connect(self.__topicSubscribed) - self.__client.onUnsubscribe.connect(self.__topicUnsubscribed) + client.onConnect.connect(self.__brokerConnected) + client.onDisconnected.connect(self.__brokerDisconnected) + client.onLog.connect(self.__clientLog) + client.onMessage.connect(self.__messageReceived) + client.onPublish.connect(self.__messagePublished) + client.onSubscribe.connect(self.__topicSubscribed) + client.onUnsubscribe.connect(self.__topicUnsubscribed) - self.__client.connectTimeout.connect(self.__connectTimeout) + client.connectTimeout.connect(self.__connectTimeout) + + return client ####################################################################### ## Slots handling MQTT related signals @@ -446,8 +463,7 @@ MqttConnectionProfilesDialog ) dlg = MqttConnectionProfilesDialog( - self.__client, self.__plugin.getPreferences("BrokerProfiles"), - parent=self) + self.__plugin.getPreferences("BrokerProfiles"), parent=self) if dlg.exec() == QDialog.DialogCode.Accepted: profilesDict = dlg.getProfiles() self.__plugin.setPreferences("BrokerProfiles", profilesDict) @@ -457,7 +473,7 @@ MqttConnectionOptionsDialog ) dlg = MqttConnectionOptionsDialog( - self.__client, self.__connectionOptions, parent=self) + self.__connectionOptions, parent=self) if dlg.exec() == QDialog.DialogCode.Accepted: self.__connectionOptions = dlg.getConnectionOptions() if self.__connectionOptions["TlsEnable"]: @@ -1026,8 +1042,11 @@ self.__addBrokerToRecent(host, port) self.connectButton.setEnabled(False) if self.__connectionOptions is None: + self.__client = self.__createClient() self.__client.connectToServer(host, port=port) else: + self.__client = self.__createClient( + protocol=self.__connectionOptions["Protocol"]) self.__client.connectToServerWithOptions( host, port=port, options=self.__connectionOptions) @@ -1040,9 +1059,13 @@ self.__plugin.setPreferences("MostRecentProfile", profileName) profilesDict = self.__plugin.getPreferences("BrokerProfiles") - profile = copy.copy(profilesDict[profileName]) # play it save - host = profile["BrokerAddress"] - port = profile["BrokerPort"] + connectionProfile = copy.copy(profilesDict[profileName]) + host = connectionProfile["BrokerAddress"] + port = connectionProfile["BrokerPort"] + try: + protocol = connectionProfile["Protocol"] + except KeyError: + protocol = MqttProtocols.MQTTv311 self.brokerStatusLabel.setText( self.tr("Connecting to {0}:{1} ...").format( @@ -1050,5 +1073,7 @@ self.brokerStatusLabel.show() self.connectButton.setEnabled(False) - self.__client.connectToServerWithOptions(host, port=port, - options=profile) + + self.__client = self.__createClient(protocol=protocol) + self.__client.connectToServerWithOptions( + host, port=port, options=connectionProfile)