diff --git a/package-lock.json b/package-lock.json
index 77b548c5698e2002ff56d6586cbe055ece79822a..0d328d4c72d6fc5596a0aad2ecb0165af8d38024 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10300,6 +10300,11 @@
       "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz",
       "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw=="
     },
+    "js-sdsl": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-2.1.4.tgz",
+      "integrity": "sha512-/Ew+CJWHNddr7sjwgxaVeIORIH4AMVC9dy0hPf540ZGMVgS9d3ajwuVdyhDt6/QUvT8ATjR3yuYBKsS79F+H4A=="
+    },
     "js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -11079,9 +11084,9 @@
       }
     },
     "mqtt": {
-      "version": "4.2.8",
-      "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-4.2.8.tgz",
-      "integrity": "sha512-DJYjlXODVXtSDecN8jnNzi6ItX3+ufGsEs9OB3YV24HtkRrh7kpx8L5M1LuyF0KzaiGtWr2PzDcMGAY60KGOSA==",
+      "version": "4.3.5",
+      "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-4.3.5.tgz",
+      "integrity": "sha512-l29WGHAc0EayK1cjb6moozc+rlgK6YRCPbP3zB1CrJw84Bjk4kG9EJCXojdn4r29lA80SCqxRKq1QJ87+Xevng==",
       "requires": {
         "commist": "^1.0.0",
         "concat-stream": "^2.0.0",
@@ -11089,13 +11094,16 @@
         "duplexify": "^4.1.1",
         "help-me": "^3.0.0",
         "inherits": "^2.0.3",
+        "lru-cache": "^6.0.0",
         "minimist": "^1.2.5",
         "mqtt-packet": "^6.8.0",
+        "number-allocator": "^1.0.9",
         "pump": "^3.0.0",
         "readable-stream": "^3.6.0",
         "reinterval": "^1.1.0",
+        "rfdc": "^1.3.0",
         "split2": "^3.1.0",
-        "ws": "^7.5.0",
+        "ws": "^7.5.5",
         "xtend": "^4.0.2"
       },
       "dependencies": {
@@ -11132,9 +11140,9 @@
           }
         },
         "ws": {
-          "version": "7.5.5",
-          "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz",
-          "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w=="
+          "version": "7.5.7",
+          "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz",
+          "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A=="
         }
       }
     },
@@ -11574,6 +11582,25 @@
       "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
       "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4="
     },
+    "number-allocator": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.9.tgz",
+      "integrity": "sha512-sIIF0dZKMs3roPUD7rLreH8H3x47QKV9dHZ+PeSnH24gL0CxKxz/823woGZC0hLBSb2Ar/rOOeHiNbnPBum/Mw==",
+      "requires": {
+        "debug": "^4.3.1",
+        "js-sdsl": "^2.1.2"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "4.3.3",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
+          "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
+          "requires": {
+            "ms": "2.1.2"
+          }
+        }
+      }
+    },
     "nwsapi": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz",
@@ -14283,6 +14310,11 @@
       "resolved": "https://registry.npmjs.org/rework-visit/-/rework-visit-1.0.0.tgz",
       "integrity": "sha1-mUWygD8hni96ygCtuLyfZA+ELJo="
     },
+    "rfdc": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz",
+      "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA=="
+    },
     "rgb-regex": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz",
diff --git a/src/App.js b/src/App.js
index 8a2e97cb26011a5bfee6e4a5a067cc7beea20e01..3bd90d7e416050cf119cc00428ce33543c4c08da 100644
--- a/src/App.js
+++ b/src/App.js
@@ -2,32 +2,17 @@ import React from 'react';
 
 import { BrowserRouter, Switch, Route } from 'react-router-dom';
 
-import mqtt from 'mqtt';
-
 import EntryPage from './components/entry-page/entry-page';
 import ErrorDialog from './components/dialog/error-dialog.js';
 import ExperimentOverview from './components/experiment-overview/experiment-overview';
 import SimulationView from './components/simulation-view/simulation-view';
 import NotificationDialog from './components/dialog/notification-dialog.js';
+import MqttClientService from './services/nrp-core/mqtt-client-service';
 
 class App extends React.Component {
 
   componentDidMount() {
-    console.info(window.location);
-    const client = mqtt.connect('ws://' + window.location.hostname + ':9000/mqtt');
-    client.on('connect', () => {
-      console.info('MQTT connected');
-      console.info(client);
-    });
-    client.on('error', (error) => {
-      console.error(error);
-    });
-    client.on('message', (topic, payload, packet) => {
-      console.info('MQTT message');
-      console.info(topic);
-      console.info(payload);
-      console.info(packet);
-    });
+    MqttClientService.instance.connect('ws://' + window.location.hostname + ':1884');
   }
 
   render() {
diff --git a/src/services/nrp-core/mqtt-client-service.js b/src/services/nrp-core/mqtt-client-service.js
new file mode 100644
index 0000000000000000000000000000000000000000..ca824d4e406841a5f20eec25677e67a03304b769
--- /dev/null
+++ b/src/services/nrp-core/mqtt-client-service.js
@@ -0,0 +1,51 @@
+import mqtt from 'mqtt';
+
+let _instance = null;
+const SINGLETON_ENFORCER = Symbol();
+
+/**
+ * Service handling state and info of running simulations.
+ */
+export default class MqttClientService {
+  constructor(enforcer) {
+    if (enforcer !== SINGLETON_ENFORCER) {
+      throw new Error('Use ' + this.constructor.name + '.instance');
+    }
+  }
+
+  static get instance() {
+    if (_instance == null) {
+      _instance = new MqttClientService(SINGLETON_ENFORCER);
+    }
+
+    return _instance;
+  }
+
+  connect(brokerUrl) {
+    console.info('MQTT connecting to ' + brokerUrl + ' ...');
+    this.client = mqtt.connect(brokerUrl);
+    this.client.on('connect', () => {
+      console.info('... MQTT connected');
+      console.info(this.client);
+    });
+    this.client.on('error', this.onError);
+    this.client.on('message', this.onMessage);
+
+    this.client.subscribe('#', (err) => {
+      if (err) {
+        console.error(err);
+      }
+    });
+  }
+
+  onError(error) {
+    console.error(error);
+  }
+
+  onMessage(topic, payload, packet) {
+    console.info('MQTT message');
+    console.info(topic);
+    console.info(payload);
+    console.info(packet);
+  }
+}
\ No newline at end of file