1
|
import logging
|
2
|
import math
|
3
|
|
4
|
import matplotlib.pyplot as plt
|
5
|
from PyQt5 import QtGui
|
6
|
from PyQt5.QtCore import QSize, QThread, QObject, pyqtSignal
|
7
|
from PyQt5.QtWidgets import QMainWindow, QWidget, QMenuBar, QAction
|
8
|
from PyQt5.QtWidgets import QVBoxLayout
|
9
|
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
10
|
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
|
11
|
|
12
|
from aswi2021vochomurka.model.Message import Message
|
13
|
from aswi2021vochomurka.service.mqtt.mqtt_subscriber import MQTTSubscriber
|
14
|
from aswi2021vochomurka.service.subscriber import Subscriber
|
15
|
from aswi2021vochomurka.service.subscriber_callback import SubscriberCallback
|
16
|
from aswi2021vochomurka.service.subscriber_params import SubscriberParams, ConnectionParams
|
17
|
from aswi2021vochomurka.view.about import AboutDialog
|
18
|
from aswi2021vochomurka.view.help import HelpDialog
|
19
|
from aswi2021vochomurka.view.logger_view import LoggerView
|
20
|
from aswi2021vochomurka.view.settings import SettingsDialog
|
21
|
|
22
|
|
23
|
class Worker(QObject, SubscriberCallback):
|
24
|
connected = pyqtSignal()
|
25
|
disconnected = pyqtSignal()
|
26
|
error = pyqtSignal(Exception)
|
27
|
newMessage = pyqtSignal(Message)
|
28
|
subscriber: Subscriber = None
|
29
|
|
30
|
params = SubscriberParams(
|
31
|
["/home/1", "/home/2"],
|
32
|
10,
|
33
|
ConnectionParams("localhost", 1883, 60),
|
34
|
True
|
35
|
)
|
36
|
|
37
|
def start(self):
|
38
|
self.subscriber = MQTTSubscriber(self, self.params)
|
39
|
self.subscriber.start()
|
40
|
|
41
|
def stop(self):
|
42
|
self.subscriber.stop()
|
43
|
|
44
|
def onConnected(self):
|
45
|
self.connected.emit()
|
46
|
|
47
|
def onDisconnected(self):
|
48
|
self.disconnected.emit()
|
49
|
|
50
|
def onError(self):
|
51
|
self.error.emit()
|
52
|
|
53
|
def onMessage(self, message: Message):
|
54
|
self.newMessage.emit(message)
|
55
|
pass
|
56
|
|
57
|
def onCloseTopic(self, topic: str):
|
58
|
pass
|
59
|
|
60
|
|
61
|
class MainView(QMainWindow):
|
62
|
worker: Worker = None
|
63
|
workerThread: QThread = None
|
64
|
|
65
|
def __init__(self):
|
66
|
super(MainView, self).__init__()
|
67
|
|
68
|
self.chartsNum = 0
|
69
|
self.arrayData = []
|
70
|
|
71
|
self.dataIndex = 0
|
72
|
self.dataDict = {}
|
73
|
|
74
|
self.figure = plt.figure(figsize=([500,500]))
|
75
|
|
76
|
self.canvas = FigureCanvas(self.figure)
|
77
|
self.toolbar = NavigationToolbar(self.canvas, self)
|
78
|
|
79
|
self.setMinimumSize(QSize(440, 240))
|
80
|
self.setWindowTitle("MQTT client")
|
81
|
|
82
|
logger = self._createLoggerView()
|
83
|
layout = QVBoxLayout()
|
84
|
layout.addWidget(logger.widget)
|
85
|
layout.addWidget(self.toolbar)
|
86
|
layout.addWidget(self.canvas)
|
87
|
|
88
|
widget = QWidget()
|
89
|
widget.setLayout(layout)
|
90
|
self.setCentralWidget(widget)
|
91
|
self._createMenuBar()
|
92
|
|
93
|
self.initSubscriber()
|
94
|
|
95
|
def _createLoggerView(self):
|
96
|
logger = LoggerView(self)
|
97
|
formatter = logging.Formatter('%(asctime)s %(message)s', '%H:%M')
|
98
|
logger.setFormatter(formatter)
|
99
|
logger.setLevel(logging.INFO)
|
100
|
logging.getLogger('').addHandler(logger)
|
101
|
return logger
|
102
|
|
103
|
def _createMenuBar(self):
|
104
|
menuBar = QMenuBar(self)
|
105
|
settingsAction = QAction("&Settings", self)
|
106
|
settingsAction.triggered.connect(self.settings)
|
107
|
helpAction = QAction("&Help", self)
|
108
|
helpAction.triggered.connect(self.help)
|
109
|
aboutAction = QAction("&About", self)
|
110
|
aboutAction.triggered.connect(self.about)
|
111
|
menuBar.addAction(settingsAction)
|
112
|
menuBar.addAction(helpAction)
|
113
|
menuBar.addAction(aboutAction)
|
114
|
self.setMenuBar(menuBar)
|
115
|
|
116
|
def plot(self, message: Message):
|
117
|
self.figure.clear()
|
118
|
|
119
|
if message.topic in self.dataDict:
|
120
|
self.dataDict[message.topic].append(message.value)
|
121
|
else:
|
122
|
self.dataDict[message.topic] = [message.value]
|
123
|
self.chartsNum += 1
|
124
|
|
125
|
rows = math.ceil(self.chartsNum / 2)
|
126
|
|
127
|
b = 0
|
128
|
for a in self.dataDict.values():
|
129
|
self.figure.add_subplot(rows, 2, b + 1)
|
130
|
b += 1
|
131
|
plt.plot(a)
|
132
|
|
133
|
self.canvas.draw()
|
134
|
|
135
|
def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
|
136
|
self.worker.stop()
|
137
|
|
138
|
def settings(self):
|
139
|
dialog = SettingsDialog()
|
140
|
if dialog.exec_():
|
141
|
self.reconnect()
|
142
|
|
143
|
def help(self):
|
144
|
dialog = HelpDialog()
|
145
|
dialog.exec_()
|
146
|
pass
|
147
|
|
148
|
def about(self):
|
149
|
dialog = AboutDialog()
|
150
|
dialog.exec_()
|
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
|
|
161
|
def initSubscriber(self):
|
162
|
self.workerThread = QThread()
|
163
|
self.worker = Worker()
|
164
|
self.worker.moveToThread(self.workerThread)
|
165
|
self.workerThread.started.connect(self.worker.start)
|
166
|
self.worker.newMessage.connect(
|
167
|
lambda message: self.plot(message)
|
168
|
)
|
169
|
self.workerThread.start()
|