Revize 7d28568e
Přidáno uživatelem Martin Forejt před téměř 4 roky(ů)
aswi2021vochomurka/service/mqtt/mqtt_subscriber.py | ||
---|---|---|
7 | 7 |
|
8 | 8 |
|
9 | 9 |
class MQTTSubscriber(Subscriber): |
10 |
client: mqtt.Client = None |
|
10 | 11 |
|
11 | 12 |
# The callback for when the client receives a CONNACK response from the server. |
12 | 13 |
def on_connect(self, client, userdata, flags, rc, properties=None): |
... | ... | |
40 | 41 |
def start(self): |
41 | 42 |
super().start() |
42 | 43 |
client = mqtt.Client() |
44 |
self.client = client |
|
43 | 45 |
client.on_connect = self.on_connect |
44 | 46 |
client.on_message = self.on_message |
45 | 47 |
client.on_disconnect = self.on_disconnect |
... | ... | |
63 | 65 |
return |
64 | 66 |
|
65 | 67 |
client.loop_forever() |
68 |
|
|
69 |
def stop(self): |
|
70 |
super().stop() |
|
71 |
if self.client is not None: |
|
72 |
logging.info("Disconnecting from broker") |
|
73 |
client = self.client |
|
74 |
self.client = None |
|
75 |
client.disconnect() |
aswi2021vochomurka/service/subscriber.py | ||
---|---|---|
1 | 1 |
import time |
2 |
from typing import Dict |
|
2 | 3 |
|
3 | 4 |
from apscheduler.schedulers.background import BackgroundScheduler |
5 |
from apscheduler.schedulers.base import STATE_STOPPED |
|
4 | 6 |
|
5 | 7 |
from aswi2021vochomurka.model.Message import Message |
6 | 8 |
from aswi2021vochomurka.service.file_manager import FileManager |
7 | 9 |
from aswi2021vochomurka.service.subscriber_callback import SubscriberCallback |
8 | 10 |
from aswi2021vochomurka.service.subscriber_params import SubscriberParams |
9 |
from typing import Dict |
|
10 | 11 |
|
11 | 12 |
|
12 | 13 |
class Subscriber: |
13 | 14 |
callback: SubscriberCallback |
14 | 15 |
params: SubscriberParams |
15 | 16 |
|
16 |
scheduler = BackgroundScheduler()
|
|
17 |
scheduler: BackgroundScheduler
|
|
17 | 18 |
files: Dict[str, FileManager] = {} |
18 | 19 |
|
19 | 20 |
def __init__(self, callback: SubscriberCallback, params: SubscriberParams): |
... | ... | |
22 | 23 |
|
23 | 24 |
def start(self): |
24 | 25 |
# start scheduler to check closed topics |
26 |
self.scheduler = BackgroundScheduler() |
|
25 | 27 |
self.scheduler.add_job(self.check_closed_topics, 'interval', seconds=self.params.closeLimit) |
26 | 28 |
self.scheduler.start() |
27 | 29 |
|
28 | 30 |
def stop(self): |
29 |
self.scheduler.shutdown() |
|
31 |
if self.scheduler.state != STATE_STOPPED: |
|
32 |
self.scheduler.shutdown() |
|
30 | 33 |
self.close_files() |
31 | 34 |
|
32 | 35 |
def close_files(self): |
33 | 36 |
for topic in self.files: |
34 | 37 |
self.files.get(topic).close() |
35 |
self.files = {}
|
|
38 |
self.files.clear()
|
|
36 | 39 |
|
37 | 40 |
def check_closed_topics(self): |
38 | 41 |
t = time.time() |
aswi2021vochomurka/view/main_view.py | ||
---|---|---|
2 | 2 |
import math |
3 | 3 |
|
4 | 4 |
import matplotlib.pyplot as plt |
5 |
from PyQt5 import QtGui |
|
5 | 6 |
from PyQt5.QtCore import QSize, QThread, QObject, pyqtSignal |
6 | 7 |
from PyQt5.QtWidgets import QMainWindow, QWidget, QMenuBar, QAction |
7 | 8 |
from PyQt5.QtWidgets import QVBoxLayout |
... | ... | |
23 | 24 |
connected = pyqtSignal() |
24 | 25 |
disconnected = pyqtSignal() |
25 | 26 |
error = pyqtSignal(Exception) |
26 |
newMessage = pyqtSignal(str)
|
|
27 |
newMessage = pyqtSignal(Message)
|
|
27 | 28 |
subscriber: Subscriber = None |
28 | 29 |
|
29 | 30 |
params = SubscriberParams( |
... | ... | |
37 | 38 |
self.subscriber = MQTTSubscriber(self, self.params) |
38 | 39 |
self.subscriber.start() |
39 | 40 |
|
41 |
def stop(self): |
|
42 |
self.subscriber.stop() |
|
43 |
|
|
40 | 44 |
def onConnected(self): |
41 | 45 |
self.connected.emit() |
42 | 46 |
|
... | ... | |
47 | 51 |
self.error.emit() |
48 | 52 |
|
49 | 53 |
def onMessage(self, message: Message): |
50 |
self.newMessage.emit(message.topic)
|
|
51 |
self.window.plot(message)
|
|
54 |
self.newMessage.emit(message) |
|
55 |
pass
|
|
52 | 56 |
|
53 | 57 |
def onCloseTopic(self, topic: str): |
54 | 58 |
pass |
... | ... | |
128 | 132 |
|
129 | 133 |
self.canvas.draw() |
130 | 134 |
|
135 |
def closeEvent(self, a0: QtGui.QCloseEvent) -> None: |
|
136 |
self.worker.stop() |
|
137 |
|
|
131 | 138 |
def settings(self): |
132 | 139 |
dialog = SettingsDialog() |
133 |
dialog.exec_() |
|
140 |
if dialog.exec_(): |
|
141 |
self.reconnect() |
|
134 | 142 |
|
135 | 143 |
def help(self): |
136 | 144 |
dialog = HelpDialog() |
... | ... | |
141 | 149 |
dialog = AboutDialog() |
142 | 150 |
dialog.exec_() |
143 | 151 |
|
152 |
def disconnect(self): |
|
153 |
self.worker.stop() |
|
154 |
self.workerThread.quit() |
|
155 |
self.workerThread.wait() |
|
156 |
|
|
157 |
def reconnect(self): |
|
158 |
self.disconnect() |
|
159 |
self.workerThread.start() |
|
160 |
|
|
144 | 161 |
def initSubscriber(self): |
145 | 162 |
self.workerThread = QThread() |
146 | 163 |
self.worker = Worker() |
147 | 164 |
self.worker.moveToThread(self.workerThread) |
148 | 165 |
self.workerThread.started.connect(self.worker.start) |
149 |
# self.worker.newMessage.connect( |
|
150 |
# lambda message: self.b.insertPlainText(message + "\n") |
|
151 |
# ) |
|
152 |
self.worker.window = self |
|
166 |
self.worker.newMessage.connect( |
|
167 |
lambda message: self.plot(message) |
|
168 |
) |
|
153 | 169 |
self.workerThread.start() |
aswi2021vochomurka/view/settings.py | ||
---|---|---|
1 |
from PyQt5.QtWidgets import QDialog |
|
1 |
from PyQt5 import QtCore |
|
2 |
from PyQt5.QtCore import QSettings, QSize |
|
3 |
from PyQt5.QtGui import QStandardItemModel, QStandardItem |
|
4 |
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QDialogButtonBox, QGroupBox, QFormLayout, QLabel, QLineEdit, QSpinBox, \ |
|
5 |
QCheckBox, QListView, QWidget, QPushButton, QHBoxLayout, QListWidget, QListWidgetItem, QTableWidget |
|
2 | 6 |
|
3 | 7 |
|
4 | 8 |
class SettingsDialog(QDialog): |
9 |
topics = ['/home/1', '/home/2'] |
|
10 |
|
|
5 | 11 |
def __init__(self): |
6 | 12 |
super(SettingsDialog, self).__init__() |
7 |
|
|
13 |
self.settings = QSettings("Vochomurka", "MQTTClient") |
|
8 | 14 |
self.setWindowTitle("Settings") |
15 |
self.setMinimumSize(QSize(600, 500)) |
|
16 |
|
|
17 |
connectionGroupBox = QGroupBox("Connection") |
|
18 |
connectionLayout = QFormLayout() |
|
19 |
self.hostInput = QLineEdit(self.settings.value("connection_host", "localhost", str)) |
|
20 |
connectionLayout.addRow(QLabel("Host:"), self.hostInput) |
|
21 |
self.portInput = QSpinBox() |
|
22 |
self.portInput.setMaximum(65535) |
|
23 |
self.portInput.setValue(self.settings.value("connection_port", 1883, int)) |
|
24 |
connectionLayout.addRow(QLabel("Port:"), self.portInput) |
|
25 |
self.keepaliveInput = QSpinBox() |
|
26 |
self.keepaliveInput.setMaximum(1000) |
|
27 |
self.keepaliveInput.setValue(self.settings.value("connection_keepalive", 60, int)) |
|
28 |
connectionLayout.addRow(QLabel("Keepalive(s):"), self.keepaliveInput) |
|
29 |
self.anonymousInput = QCheckBox() |
|
30 |
self.anonymousInput.setChecked(self.settings.value("connection_anonymous", True, bool)) |
|
31 |
self.anonymousInput.stateChanged.connect(self.anonymousChanged) |
|
32 |
connectionLayout.addRow(QLabel("Anonymous:"), self.anonymousInput) |
|
33 |
self.usernameInput = QLineEdit(self.settings.value("connection_username", "", str)) |
|
34 |
connectionLayout.addRow(QLabel("Username:"), self.usernameInput) |
|
35 |
self.passwordInput = QLineEdit(self.settings.value("connection_password", "", str)) |
|
36 |
connectionLayout.addRow(QLabel("Password:"), self.passwordInput) |
|
37 |
self.anonymousChanged() |
|
38 |
connectionGroupBox.setLayout(connectionLayout) |
|
39 |
|
|
40 |
topicsGroupBox = QGroupBox("Topics") |
|
41 |
topicsLayout = QFormLayout() |
|
42 |
|
|
43 |
self.topicsListWidget = QListWidget() |
|
44 |
for topic in self.topics: |
|
45 |
item = QListWidgetItem() |
|
46 |
item.setText(topic) |
|
47 |
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable) |
|
48 |
self.topicsListWidget.addItem(item) |
|
49 |
|
|
50 |
topicsLayout.addRow(self.topicsListWidget) |
|
51 |
add = QPushButton("Add") |
|
52 |
add.setFixedWidth(60) |
|
53 |
add.clicked.connect(self.addTopic) |
|
54 |
remove = QPushButton("Remove") |
|
55 |
remove.setFixedWidth(60) |
|
56 |
remove.clicked.connect(self.removeTopic) |
|
57 |
topicsLayout.addRow(add, remove) |
|
58 |
|
|
59 |
self.timeoutInput = QSpinBox() |
|
60 |
self.timeoutInput.setMaximum(1000) |
|
61 |
self.timeoutInput.setToolTip("Unsubscribe topic and close file when there is not new message after this " |
|
62 |
"timeout (in seconds) expires") |
|
63 |
timeoutLabel = QLabel("Topic timeout(s):") |
|
64 |
timeoutLabel.setToolTip("Unsubscribe topic and close file when there is not new message after this " |
|
65 |
"timeout (in seconds) expires") |
|
66 |
self.timeoutInput.setValue(self.settings.value("topic_timeout", 60, int)) |
|
67 |
topicsLayout.addRow(timeoutLabel, self.timeoutInput) |
|
68 |
|
|
69 |
topicsGroupBox.setLayout(topicsLayout) |
|
70 |
|
|
71 |
buttonBox = QDialogButtonBox() |
|
72 |
buttonBox.addButton("Save and Reconnect", QDialogButtonBox.AcceptRole) |
|
73 |
buttonBox.addButton("Cancel", QDialogButtonBox.RejectRole) |
|
74 |
buttonBox.accepted.connect(self.accept) |
|
75 |
buttonBox.rejected.connect(self.reject) |
|
76 |
|
|
77 |
mainLayout = QVBoxLayout() |
|
78 |
mainLayout.addWidget(connectionGroupBox) |
|
79 |
mainLayout.addWidget(topicsGroupBox) |
|
80 |
mainLayout.addWidget(buttonBox) |
|
81 |
self.setLayout(mainLayout) |
|
82 |
|
|
83 |
def addTopic(self): |
|
84 |
item = QListWidgetItem() |
|
85 |
item.setText("/topic") |
|
86 |
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable) |
|
87 |
self.topicsListWidget.addItem(item) |
|
88 |
|
|
89 |
def removeTopic(self): |
|
90 |
for item in self.topicsListWidget.selectedItems(): |
|
91 |
self.topicsListWidget.takeItem(self.topicsListWidget.row(item)) |
|
92 |
|
|
93 |
def anonymousChanged(self): |
|
94 |
self.usernameInput.setEnabled(not self.anonymousInput.isChecked()) |
|
95 |
self.passwordInput.setEnabled(not self.anonymousInput.isChecked()) |
|
96 |
|
|
97 |
def accept(self) -> None: |
|
98 |
super().accept() |
|
99 |
self.topics = self.topicsListWidget.item(0).text() |
|
100 |
print(self.topics) |
|
101 |
self.settings.setValue("connection_host", self.hostInput.text()) |
|
102 |
self.settings.setValue("connection_port", self.portInput.value()) |
|
103 |
self.settings.setValue("connection_keepalive", self.keepaliveInput.value()) |
|
104 |
self.settings.setValue("connection_anonymous", self.anonymousInput.isChecked()) |
|
105 |
self.settings.setValue("connection_username", self.usernameInput.text()) |
|
106 |
self.settings.setValue("connection_password", self.passwordInput.text()) |
Také k dispozici: Unified diff
Re: #8921 - settings dialog