diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index a0c74564837f3ddbee501fd0616509080b42e130..27f058b478d166a4da961710494434ae9fdbe458 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -16,8 +16,8 @@ Build Wheel:
     - legacy
   script:
     - pip install -r requirements.txt
-    - python setup.py sdist bdist_wheel
-#
+    - python build
+
 Push Wheel to Package Registry:
   image: python:3.9
   tags:
@@ -32,6 +32,20 @@ Push Wheel to Package Registry:
     - pip install twine
     - python -m twine upload -u gitlab-ci-token -p $CI_JOB_TOKEN --verbose --repository-url https://git-ce.rwth-aachen.de/api/v4/projects/${CI_PROJECT_ID}/packages/pypi dist/*
 
+Publish on PyPI:
+  image: python:3.9
+  tags:
+    - frodo
+  stage: push
+  artifacts:
+    paths:
+      - dist/*
+  only:
+    - master
+  script:
+    - pip install twine
+    - python -m twine upload -u __token__ -p $PyPIToken dist/*
+
 pages:
   image: python:3.9
   stage: deploy
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000000000000000000000000000000000000..cfec06bb92c0da5037d143b0e24b03ac14006e9b
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1 @@
+include PyPI-README.md
\ No newline at end of file
diff --git a/PyPI-README.md b/PyPI-README.md
new file mode 100644
index 0000000000000000000000000000000000000000..fcb726a97339598c486da5a0e6ea6dc6eaee9f2c
--- /dev/null
+++ b/PyPI-README.md
@@ -0,0 +1,114 @@
+# WZL-MQTT
+
+Current stable version: 2.5.1
+
+## Documentation
+
+For the full API documentation, view [https://iot.wzl-mq.rwth-aachen.de/documentation/libs/mqtt/](https://iot.wzl-mq.rwth-aachen.de/documentation/libs/mqtt/).
+
+## Installation
+Requires at least Python 3.6
+
+1. Install the WZL-MQTT package via pip  
+```
+pip install wzl-mqtt
+```
+
+## Usage
+
+### Publish messages
+
+```python
+from wzl import mqtt
+
+# username and password required to connect to the broker
+MQTT_USER = ""
+MQTT_PASSWORD = ""
+
+# address, port and virtual host of the broker to connect to 
+MQTT_BROKER = "127.0.0.1"
+MQTT_PORT = 1883
+MQTT_VHOST = "/"
+
+# initialize publisher and connect to the broker
+client = mqtt.MQTTPublisher()
+client.connect(MQTT_BROKER, MQTT_USER, MQTT_PASSWORD, vhost=MQTT_VHOST, port=MQTT_PORT)
+
+# create message and publish the message as UTF-8 encoded string
+message = json.dumps({"value": [random.uniform(0, 5) for i in range(3)], "timestamp": datetime.datetime.utcnow().isoformat() + "Z",
+                                  "covariance": [[2, 0, 0], [0, 2, 0], [0, 0, 0]], "nonce": str(uuid.uuid4()), "hash": None, "unit": "MTR"})
+client.publish(MQTT_USER + "/channel-001", message.encode("utf-8"))
+```
+
+### Subscribe to topics and receive messages
+```python
+from wzl import mqtt
+
+# username and password required to connect to the broker
+MQTT_USER = ""
+MQTT_PASSWORD = ""
+
+# address, port and virtual host of the broker to connect to 
+MQTT_BROKER = "127.0.0.1"
+MQTT_PORT = 1883
+MQTT_VHOST = "/"
+
+# initialize logger
+logger = mqtt.Logger.get('Receiver') # change 'Receiver' to any string you like
+
+# define callback which will be executed when a message is received
+def print_mqtt_message(topic, message):
+        logger.info("### {} ###\r\n{}\r\n".format(topic, message.decode("utf-8")))
+
+# initialize subscriber and connect to the broker   
+client = mqtt.MQTTSubscriber()
+client.connect(MQTT_BROKER, MQTT_USER, MQTT_PASSWORD, vhost=MQTT_VHOST, port=MQTT_PORT)
+
+# register the callback and subscribe topic
+client.set_callback("PRINT", print_mqtt_message)
+client.subscribe('#')
+
+# start waiting loop to prevent program from exiting
+while True:
+    try:
+        time.sleep(1)
+    except KeyboardInterrupt:
+        break
+
+```
+
+## Changelog
+2.5.1
+  - increased verbosity in case of errors by including the full stack trace
+
+2.5.0
+  - changed signature of connect method
+    - specifying the port is optional now, if not specified the port automatically is derived from the "websocket" and "ssl" flags
+    
+2.4.2
+  - fixed a bug of websocket connection
+
+2.4.1
+- made the error message of code 1 more precise
+
+2.4.0
+- added vhost parameter to connect function of client
+- changed default logging behaviour
+  - now by default logging is only written to console
+  - if logging should also create log-files, the logger must be explicitly initialized
+
+2.3.0
+- a prefix can now be defined which is prepended to every published or subscribed topic
+
+2.2.0
+- it is possible to connect with more than one client with an identical username to the broker
+
+2.1.0
+- removed wzl-utilities dependency
+
+2.0.0
+- renamed the MQTReceiver to MQTTSubscriber for the sake of convenience
+- added extensive documentation
+
+1.3.0
+- added wzl-utilities dependency by sourcing out logging functionality
diff --git a/README.md b/README.md
index 3549171b07e7f9cdd3064f4bdf7c47f671ff2e1c..c5d135c447112647ecfd8d4f579e93d529c17d93 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,4 @@
 # WZL-MQTT
-[![pipeline status](https://git-ce.rwth-aachen.de/wzl-mq-ms/forschung-lehre/digital-mars/mqtt/badges/master/pipeline.svg)](https://git-ce.rwth-aachen.de/wzl-mq-ms/forschung-lehre/digital-mars/mqtt/badges/master)
 
 Current stable version: 2.5.1
 
diff --git a/build.bat b/build.bat
deleted file mode 100644
index a287c004fa790148f6fc51ea1b62546fb109ef1f..0000000000000000000000000000000000000000
--- a/build.bat
+++ /dev/null
@@ -1,5 +0,0 @@
-@echo off
-rmdir dist /s /q
-rmdir build /s /q
-rmdir wzl_mqtt.egg-info /s /q
-python setup.py bdist_wheel
\ No newline at end of file
diff --git a/environment.yml b/environment.yml
deleted file mode 100644
index 34fee2d492a89fd02aa4efb84ef50de0a2bb0daa..0000000000000000000000000000000000000000
--- a/environment.yml
+++ /dev/null
@@ -1,43 +0,0 @@
-name: 5f49f249-b55b-4f31-96da-3f69ccd0a975
-channels:
-  - defaults
-dependencies:
-  - ca-certificates=2020.12.5=h5b45459_0
-  - certifi=2020.12.5=py38haa244fe_1
-  - openssl=1.1.1k=h8ffe710_0
-  - paho-mqtt=1.5.1=pyhd3deb0d_0
-  - pip=21.0.1=pyhd8ed1ab_0
-  - python=3.8.8=h7840368_0_cpython
-  - python_abi=3.8=1_cp38
-  - setuptools=49.6.0=py38haa244fe_3
-  - sqlite=3.35.2=h8ffe710_0
-  - vc=14.2=hb210afc_4
-  - vs2015_runtime=14.28.29325=h5e1d092_4
-  - wheel=0.36.2=pyhd3deb0d_0
-  - wincertstore=0.2=py38haa244fe_1006
-  - pip:
-    - alabaster==0.7.12
-    - babel==2.9.0
-    - chardet==4.0.0
-    - colorama==0.4.4
-    - docutils==0.16
-    - idna==2.10
-    - imagesize==1.2.0
-    - jinja2==2.11.3
-    - markupsafe==1.1.1
-    - packaging==20.9
-    - pygments==2.8.1
-    - pyparsing==2.4.7
-    - pytz==2021.1
-    - requests==2.25.1
-    - snowballstemmer==2.1.0
-    - sphinx==3.5.3
-    - sphinx-rtd-theme==0.5.1
-    - sphinxcontrib-applehelp==1.0.2
-    - sphinxcontrib-devhelp==1.0.2
-    - sphinxcontrib-htmlhelp==1.0.3
-    - sphinxcontrib-jsmath==1.0.1
-    - sphinxcontrib-qthelp==1.0.3
-    - sphinxcontrib-serializinghtml==1.1.4
-    - urllib3==1.26.4
-prefix: E:\environments\5f49f249-b55b-4f31-96da-3f69ccd0a975
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000000000000000000000000000000000000..fa7093a33c048d9db6e0eb3b4d8daa57426754e3
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,3 @@
+[build-system]
+requires = ["setuptools>=42"]
+build-backend = "setuptools.build_meta"
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 95a0b6dd28daefac36db6ca073c466fa4fa6d63f..f6973ead0bba8424f6b08c55d7d0c511e5fcd2da 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,3 +2,4 @@ jinja2<3.1
 sphinx==3.5.3
 sphinx-rtd-theme==0.5.1
 paho-mqtt==1.5.1
+build==0.8.0
diff --git a/setup.py b/setup.py
index 6a2113fd5da1d99745e1862df4de0a8bf8d80303..7fd16d1430e87d6ae00963bd9dc3232ae54c4b0b 100644
--- a/setup.py
+++ b/setup.py
@@ -1,13 +1,26 @@
 from setuptools import setup, find_packages
 
+with open("PyPI-README.md", "r", encoding="utf-8") as fh:
+    long_description = fh.read()
+
 setup(name='wzl-mqtt',
       version='2.5.1',
-      url='',
+      url='https://git-ce.rwth-aachen.de/wzl-mq-public/iot/mqtt/',
+      project_urls={
+            "Bug Tracker": "https://git-ce.rwth-aachen.de/wzl-mq-public/iot/mqtt/-/issues",
+      },
       author='Matthias Bodenbenner, Benjamin Montavon',
       author_email='m.bodenbenner@wzl-mq.rwth-aachen.de',
       description='Small library containing an MQTT publisher and receiver.',
       package_dir={'wzl': 'src'},
       packages=['wzl.mqtt'],
-      # long_description=open('./README.md').read(),
-      install_requires=['paho-mqtt'],
+      long_description=long_description,
+      long_description_content_type="text/markdown",
+      classifiers=[
+            "Programming Language :: Python :: 3",
+            "License :: OSI Approved :: MIT License",
+            "Operating System :: OS Independent",
+      ],
+      install_requires=['paho-mqtt==1.5.1'],
+      python_requires='>=3.6',
       zip_safe=False)