DEV Community

Bugfender
Bugfender

Posted on • Originally published at bugfender.com on

Using MQTT on Angular Apps

When you’re building a website that needs to be updated in real-time, your first thought is probably to add WebSockets to your application. In this article, you will learn how to add MQTT to your angular web application.

However Websockets is a low-level protocol and to use it, you’ll need to add another layer on top to manage the information you want to get. This is where MQTT protocol is handy, as it’s a higher-level protocol that simplifies working with data streams.

What is MQTT?

MQTT means Message Queuing Telemetry Transport. It’s a connectivity protocol used in the IoT world to communicate between machines, but has a whole load of other applications too. You can read more about MQTT on Wikipedia and also on the official MQTT site.

Currently, MQTT protocol is used in a lot of IoT platforms to communicate between IoT devices.Currently, MQTT protocol is used in a lot of IoT devices.

Architecture

An MQTT protocol ecosystem has the following components:

  • Publisher: Responsible for publishing MQTT messages to the system. Usually an IoT device.
  • MQTT Broker: The server that gets the published data and sends it to the corresponding subscribers.
  • Subscriber: The device that is listening for incoming data from devices.

MQTT Architecture

Publish/Subscribe Model

As we have seen in the architecture overview, MQTT uses the publish/subscribe methodology. So they don’t know each other, they just need to agree on how data is going to be sent. It also allows the use of multiple publishers or subscribers, so various clients can create an MQTT connection and subscribe to data from a single device.

MQTT Topics

An MQTT Topic is the concept used to communicate between publishers and subscribers. When a subscriber wants to get data from a device, it subscribes to a specific topic, which will be where the device publishes its data. A Topic is a hierarchical UTF-8 string, and here you have an example:

/device/garden_sensor/temperature

MQTT Over Websockets

In the introduction, we said that MQTT is a high-level protocol and the great thing is that it can use different protocols to get its job done. It can adopt its own MQTT protocol, but this protocol is not supported by web browsers; however MQTT can also be used over WebSockets connection, so we can easily use MQTT on any web browser that supports WebSockets.

Which MQTT Broker Should I Use?

There are various MQTT brokers you can use for your project. On one hand you can use cloud/hosted solutions; alternatively you can choose an on-premise option, either by installing on your own servers or using through Docker. You can see a comprehensive list of the existing brokers in this Github repo. In our case we have used the open source Eclipse Mosquitto with great success.

MQTT Client on Angular Apps

Now let’s see how can we use MQTT protocol on an Angular app. The easiest way to do it is to use some of the existing Javascript libraries. In this case, we will use the ngx-mqtt library. This offers support for Javascript/Typescript observables, so it’s really helpful when writing an MQTT client on an Angular app.

Installing ngx-mqtt

You have all the information on the library site, but it’s as easy as installing the npm packages.

npm install ngx-mqtt --save

Configuration

Once the library is installed, you need to initialize it. You can follow the instructions on the ngx-mqtt site, but you will probably have multiple environments in your Angular code, so you will need a different configuration for each environment. So let’s create an mqtt section in our environment files. Here’s an example: src/environments/environment.prod.ts

export const environment = {
  production: true,
    hmr: false,
    http: {
        apiUrl: '<https://api.myweb.com>',
    },
    mqtt: {
        server: 'mqtt.myweb.com',
        protocol: "wss",
        port: 1883
    }
};

You can edit all other environment configuration files to set the right values for each one. Now we need to initialize the MQTT library, and for this we recommend changing to app.module.ts:

...
import { IMqttServiceOptions, MqttModule } from "ngx-mqtt";
import { environment as env } from '../environments/environment';

const MQTT_SERVICE_OPTIONS: IMqttServiceOptions = {
    hostname: env.mqtt.server,
    port: env.mqtt.port,
    protocol: (env.mqtt.protocol === "wss") ? "wss" : "ws",
    path: '',
};

@NgModule({
    declarations: [AppComponent],
    imports: [
        ...
        MqttModule.forRoot(MQTT_SERVICE_OPTIONS),
    ],
    ...
})
export class AppModule { }

Creating Services

With this you can now start using MQTT in your app, but to achieve a more structured code we recommend you create a service class for each Topic you are going to use. Let’s create a service that subscribes to a topic called events , where the Topic name is similar to /events/deviceid. For this we create the Typescript file src/app/services/event.mqtt.service.tswith the following code:

import { Injectable } from '@angular/core';
import { IMqttMessage, MqttService } from "ngx-mqtt";
import { Observable } from "rxjs";

@Injectable()
export class EventMqttService {

  private endpoint: string;

  constructor(
    private _mqttService: MqttService,
  ) {
    this.endpoint = 'events';
  }

  topic(deviceId: string): Observable<IMqttMessage> {
    let topicName = `/${this.endpoint}/${deviceId}`;     
    return this._mqttService.observe(topicName);
  }
}

Using this service class, we have all the MQTT-related code in a single file and now we only need to use this service when it’s needed.

Remember to add all the services files to the providers section of your AppModule, otherwise you won’t be able to use them.

Using the MQTT Services

Now it’s time to use the MQTT services we have created. So, for example, let’s create an EventStream component that prints all the events that a device generates. The code of this file will be similar to:

import { Component, OnInit } from '@angular/core';
import { EventDataModel } from 'app/models/event.model';
import { Subscription } from 'rxjs';
import { EventMqttService } from 'app/services/api/event.mqtt.service';
import { IMqttMessage } from "ngx-mqtt";

@Component({
    selector: 'event-stream',
    templateUrl: './event-stream.component.html',
    styleUrls: ['./event-stream.component.scss'],
})
export class EventStreamComponent implements OnInit {
    events: any[];
    private deviceId: string;
    subscription: Subscription;

    constructor(
        private readonly eventMqtt: EventMqttService,
    ) {
    }

    ngOnInit() {
        this.subscribeToTopic();
    }

    ngOnDestroy(): void {
        if (this.subscription) {
            this.subscription.unsubscribe();
        }
    }

    private subscribeToTopic() {
        this.subscription = this.eventMqtt.topic(this.deviceId)
            .subscribe((data: IMqttMessage) => {
                let item = JSON.parse(data.payload.toString());
                                this.events.push(item);
            });
    }
}

It’s important to remember that we need to unsubscribe from the subscription when we destroy the component.

Now, we should have an Angular app that can subscribe to MQTT topics and show the user the information every time a device generates an MQTT message.

Debugging MQTT Angular Apps

When working with Angular and MQTT, there are more moving parts than in common Angular apps where you have your Javascript frontend and a RESTFul API to consume (usually also a Javascript backend). We can list a few extra things you need to take care of:

  • Websockets : they are not easy to debug with current browsers, especially when using MQTT as data is sent in binary format.
  • MQTT Broker: this is a new component you need to take care of and make sure you have the right configuration for each environment.
  • Devices: you might be able to test the app on some devices, but once the app is live in production, the users might have some devices you didn’t know about, or a firmware update of a device can break your code.

Websockets Google Chrome debugging

Google Chrome Websockets debugging. As you can see, information is hard to read because it’s shown in binary format.

This is why Bugfender can be really helpful in debugging MQTT Angular apps. You’ll probably experience some bugs when developing the app and trying to use it in the production environment, and probably also when the app is used in the real world.

If you use Bugfender, you’ll be able to get all the Javascript exceptions that occur among your final users and if a device breaks your code, you’ll also be able to inspect the MQTT data that individual devices are sending. Moreover, Bugfender sends all console logs to our serves so you can see everything that’s happening in your Javasacript app remotely.

If you want to know how to install Bugfender in your Angular app, you can check the BugfenderSDK Angular App Sample.

Install Bugfender:

npm i @bugfender/sdk

Initiate the library in your AppModule :

Bugfender.init({
    appKey: '<YOUR_APP_KEY_HERE>',
    version: '<version>',
    build: '<build>',
});

If you don’t have an App Key you can get a free one just signing up in Bugfender.

We recommend you install a custom error handler so if there’s any Javascript exception, this is sent to Bugfender.

Now, let’s update our component. We send the MQTT messages we get to Bugfender, so later we can check whether there’s any problem with the information sent by a particular device.

...
private subscribeToTopics() {
        this.subscription = this.eventMqtt.topic(this.deviceId)
            .subscribe((data: IMqttMessage) => {
                let item = JSON.parse(data.payload.toString());

                                Bugfender.sendLog({tag: 'MQTT', text: "Got data from device " + this.deviceId})
                Bugfender.log(item);

                this.events.push(item);
            });
}   

We also recommend that you add a log when a subscription to a topic is created, so you will know which device is causing problems.

Bugfender remote console log

Bugender Log Viewer with MQTT debugging information

As you can see in the screenshot, we can easily identify the sensor that is sending the data and the data that is being sent.

The good thing about using Bugfender is that you can enable or disable specific devices, so you can enable a certain device when you know there’s a problem and won’t waste logs with useless information.

The Bugfender JS SDK is our new SDK to complement the native iOS and Android SDK. We are continuously creating new tutorials and content to help the JS developer community. If you want to be notified when new JS tutorials are available you can join our quarterly newsletter in the box below.

Top comments (0)