commit dc7a41b7ee13cde6f47dae9a041ba3349ffa0431
Author: Martin Forejt <mforejt@students.zcu.cz>
Date:   Wed Apr 21 09:47:15 2021 +0000

    Feature/mqtt demo

diff --git a/aswi2021vochomurka/app.py b/aswi2021vochomurka/app.py
new file mode 100644
index 0000000..95d3d70
--- /dev/null
+++ b/aswi2021vochomurka/app.py
@@ -0,0 +1,10 @@
+from PyQt5.QtWidgets import QApplication
+
+from aswi2021vochomurka.view.main_view import MainView
+
+
+class Application(QApplication):
+    def __init__(self, sys_argv):
+        super(Application, self).__init__(sys_argv)
+        self.main_view = MainView()
+        self.main_view.show()
diff --git a/aswi2021vochomurka/main.py b/aswi2021vochomurka/main.py
index 739d1f1..f6a4a45 100644
--- a/aswi2021vochomurka/main.py
+++ b/aswi2021vochomurka/main.py
@@ -1,2 +1,9 @@
+import sys
+
+from aswi2021vochomurka.app import Application
+
+
 def start():
     print("hello world Vochomurka")
+    app = Application(sys.argv)
+    sys.exit(app.exec_())
diff --git a/aswi2021vochomurka/service/__init__.py b/aswi2021vochomurka/service/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/aswi2021vochomurka/service/mqtt/mqtt_subscriber.py b/aswi2021vochomurka/service/mqtt/mqtt_subscriber.py
new file mode 100644
index 0000000..850ccad
--- /dev/null
+++ b/aswi2021vochomurka/service/mqtt/mqtt_subscriber.py
@@ -0,0 +1,36 @@
+import paho.mqtt.client as mqtt
+
+from aswi2021vochomurka.service.subscriber import Subscriber
+
+
+class MQTTSubscriber(Subscriber):
+
+    # The callback for when the client receives a CONNACK response from the server.
+    def on_connect(self, client, userdata, flags, rc, properties=None):
+        print("Connected with result code " + str(rc))
+        self.connected.emit()
+        # Subscribing in on_connect() means that if we lose the connection and
+        # reconnect then subscriptions will be renewed.
+        client.subscribe("#")
+
+    # The callback for when a PUBLISH message is received from the server.
+    def on_message(self, client, userdata, message):
+        print(message.topic + " " + str(message.payload.decode("utf-8")))
+        self.newMessage.emit(message.topic + " " + str(message.payload.decode("utf-8")))
+
+    def on_disconnect(self, client, userdata, rc):
+        self.disconnected.emit()
+
+    def start(self):
+        client = mqtt.Client()
+        client.on_connect = self.on_connect
+        client.on_message = self.on_message
+        client.on_disconnect = self.on_disconnect
+
+        try:
+            client.connect("localhost", 1883, 60)
+        except Exception as error:
+            self.error.emit(error)
+            return
+
+        client.loop_forever()
diff --git a/aswi2021vochomurka/service/subscriber.py b/aswi2021vochomurka/service/subscriber.py
new file mode 100644
index 0000000..9f3569a
--- /dev/null
+++ b/aswi2021vochomurka/service/subscriber.py
@@ -0,0 +1,10 @@
+from PyQt5.QtCore import pyqtSignal, QObject
+
+
+class Subscriber(QObject):
+    connected = pyqtSignal()
+    disconnected = pyqtSignal()
+    error = pyqtSignal(Exception)
+    newMessage = pyqtSignal(str)
+
+    def start(self): raise NotImplementedError
diff --git a/aswi2021vochomurka/view/__init__.py b/aswi2021vochomurka/view/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/aswi2021vochomurka/view/main_view.py b/aswi2021vochomurka/view/main_view.py
new file mode 100644
index 0000000..12b51e2
--- /dev/null
+++ b/aswi2021vochomurka/view/main_view.py
@@ -0,0 +1,33 @@
+from PyQt5.QtCore import QSize, QThread
+from PyQt5.QtWidgets import QMainWindow, QPlainTextEdit
+
+from aswi2021vochomurka.service.mqtt.mqtt_subscriber import MQTTSubscriber
+
+
+class MainView(QMainWindow):
+    worker = None
+    workerThread = None
+
+    def __init__(self):
+        QMainWindow.__init__(self)
+
+        self.setMinimumSize(QSize(440, 240))
+        self.setWindowTitle("MQTT demo")
+
+        # Add text field
+        self.b = QPlainTextEdit(self)
+        self.b.insertPlainText("App started...\n")
+        self.b.move(10, 10)
+        self.b.resize(400, 200)
+
+        self.initSubscriber()
+
+    def initSubscriber(self):
+        self.workerThread = QThread()
+        self.worker = MQTTSubscriber()
+        self.worker.moveToThread(self.workerThread)
+        self.workerThread.started.connect(self.worker.start)
+        self.worker.newMessage.connect(
+            lambda message: self.b.insertPlainText(message + "\n")
+        )
+        self.workerThread.start()
diff --git a/poetry.lock b/poetry.lock
index f41588b..bae3cf4 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,8 +1,70 @@
-package = []
+[[package]]
+name = "pyqt5"
+version = "5.15.4"
+description = "Python bindings for the Qt cross platform application toolkit"
+category = "main"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+PyQt5-Qt5 = ">=5.15"
+PyQt5-sip = ">=12.8,<13"
+
+[[package]]
+name = "pyqt5-qt5"
+version = "5.15.2"
+description = "The subset of a Qt installation needed by PyQt5."
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "pyqt5-sip"
+version = "12.8.1"
+description = "The sip module support for PyQt5"
+category = "main"
+optional = false
+python-versions = ">=3.5"
 
 [metadata]
 lock-version = "1.1"
 python-versions = "^3.8"
-content-hash = "fafb334cb038533f851c23d0b63254223abf72ce4f02987e7064b0c95566699a"
+content-hash = "095d3d22c000ec45381dc27326be154edd194e5d574bc0af2941f0cf8a385159"
 
 [metadata.files]
+pyqt5 = [
+    {file = "PyQt5-5.15.4-cp36.cp37.cp38.cp39-abi3-macosx_10_13_intel.whl", hash = "sha256:8c0848ba790a895801d5bfd171da31cad3e551dbcc4e59677a3b622de2ceca98"},
+    {file = "PyQt5-5.15.4-cp36.cp37.cp38.cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:883a549382fc22d29a0568f3ef20b38c8e7ab633a59498ac4eb63a3bf36d3fd3"},
+    {file = "PyQt5-5.15.4-cp36.cp37.cp38.cp39-none-win32.whl", hash = "sha256:a88526a271e846e44779bb9ad7a738c6d3c4a9d01e15a128ecfc6dd4696393b7"},
+    {file = "PyQt5-5.15.4-cp36.cp37.cp38.cp39-none-win_amd64.whl", hash = "sha256:213bebd51821ed89b4d5b35bb10dbe67564228b3568f463a351a08e8b1677025"},
+    {file = "PyQt5-5.15.4.tar.gz", hash = "sha256:2a69597e0dd11caabe75fae133feca66387819fc9bc050f547e5551bce97e5be"},
+]
+pyqt5-qt5 = [
+    {file = "PyQt5_Qt5-5.15.2-py3-none-macosx_10_13_intel.whl", hash = "sha256:76980cd3d7ae87e3c7a33bfebfaee84448fd650bad6840471d6cae199b56e154"},
+    {file = "PyQt5_Qt5-5.15.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:1988f364ec8caf87a6ee5d5a3a5210d57539988bf8e84714c7d60972692e2f4a"},
+    {file = "PyQt5_Qt5-5.15.2-py3-none-win32.whl", hash = "sha256:9cc7a768b1921f4b982ebc00a318ccb38578e44e45316c7a4a850e953e1dd327"},
+    {file = "PyQt5_Qt5-5.15.2-py3-none-win_amd64.whl", hash = "sha256:750b78e4dba6bdf1607febedc08738e318ea09e9b10aea9ff0d73073f11f6962"},
+]
+pyqt5-sip = [
+    {file = "PyQt5_sip-12.8.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:bb5a87b66fc1445915104ee97f7a20a69decb42f52803e3b0795fa17ff88226c"},
+    {file = "PyQt5_sip-12.8.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:a29e2ac399429d3b7738f73e9081e50783e61ac5d29344e0802d0dcd6056c5a2"},
+    {file = "PyQt5_sip-12.8.1-cp35-cp35m-win32.whl", hash = "sha256:0304ca9114b9817a270f67f421355075b78ff9fc25ac58ffd72c2601109d2194"},
+    {file = "PyQt5_sip-12.8.1-cp35-cp35m-win_amd64.whl", hash = "sha256:84ba7746762bd223bed22428e8561aa267a229c28344c2d28c5d5d3f8970cffb"},
+    {file = "PyQt5_sip-12.8.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:7b81382ce188d63890a0e35abe0f9bb946cabc873a31873b73583b0fc84ac115"},
+    {file = "PyQt5_sip-12.8.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:b6d42250baec52a5f77de64e2951d001c5501c3a2df2179f625b241cbaec3369"},
+    {file = "PyQt5_sip-12.8.1-cp36-cp36m-win32.whl", hash = "sha256:6c1ebee60f1d2b3c70aff866b7933d8d8d7646011f7c32f9321ee88c290aa4f9"},
+    {file = "PyQt5_sip-12.8.1-cp36-cp36m-win_amd64.whl", hash = "sha256:34dcd29be47553d5f016ff86e89e24cbc5eebae92eb2f96fb32d2d7ba028c43c"},
+    {file = "PyQt5_sip-12.8.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ed897c58acf4a3cdca61469daa31fe6e44c33c6c06a37c3f21fab31780b3b86a"},
+    {file = "PyQt5_sip-12.8.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:a1b8ef013086e224b8e86c93f880f776d01b59195bdfa2a8e0b23f0480678fec"},
+    {file = "PyQt5_sip-12.8.1-cp37-cp37m-win32.whl", hash = "sha256:0cd969be528c27bbd4755bd323dff4a79a8fdda28215364e6ce3e069cb56c2a9"},
+    {file = "PyQt5_sip-12.8.1-cp37-cp37m-win_amd64.whl", hash = "sha256:c9800729badcb247765e4ffe2241549d02da1fa435b9db224845bc37c3e99cb0"},
+    {file = "PyQt5_sip-12.8.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9312ec47cac4e33c11503bc1cbeeb0bdae619620472f38e2078c5a51020a930f"},
+    {file = "PyQt5_sip-12.8.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2f35e82fd7ec1e1f6716e9154721c7594956a4f5bd4f826d8c6a6453833cc2f0"},
+    {file = "PyQt5_sip-12.8.1-cp38-cp38-win32.whl", hash = "sha256:da9c9f1e65b9d09e73bd75befc82961b6b61b5a3b9d0a7c832168e1415f163c6"},
+    {file = "PyQt5_sip-12.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:832fd60a264de4134c2824d393320838f3ab648180c9c357ec58a74524d24507"},
+    {file = "PyQt5_sip-12.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c317ab1263e6417c498b81f5c970a9b1af7acefab1f80b4cc0f2f8e661f29fc5"},
+    {file = "PyQt5_sip-12.8.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:c9d6d448c29dc6606bb7974696608f81f4316c8234f7c7216396ed110075e777"},
+    {file = "PyQt5_sip-12.8.1-cp39-cp39-win32.whl", hash = "sha256:5a011aeff89660622a6d5c3388d55a9d76932f3b82c95e82fc31abd8b1d2990d"},
+    {file = "PyQt5_sip-12.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:f168f0a7f32b81bfeffdf003c36f25d81c97dee5eb67072a5183e761fe250f13"},
+    {file = "PyQt5_sip-12.8.1.tar.gz", hash = "sha256:30e944db9abee9cc757aea16906d4198129558533eb7fadbe48c5da2bd18e0bd"},
+]
diff --git a/pyproject.toml b/pyproject.toml
index 2823bd4..3eeb785 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -6,6 +6,7 @@ authors = ["Tym Vochomurka"]
 
 [tool.poetry.dependencies]
 python = "^3.8"
+PyQt5 = "^5.15.4"
 
 [tool.poetry.dev-dependencies]
 
