Link Search Menu Expand Document

MQTT Use Case

Dec 6 2023 at 12:00 AM

  1. Introduction
  2. Device Setup
  3. Example Packet
  4. Driver Config Setup
  5. C-Sharp Script Setup

Introduction

This document serves as a comprehensive guide on configuring and setting up the device, and configure it for the ‘Post Channel’ using the Accuenergy (Acuvim-II with AXM-WEB2 module) portal. The use case is explicitly used for the C-Sharp Script filter, with MQTT as the data source. Users are tasked with specifying MQTT as their data source and then define filters using the (C-Sharp Script Editor).
This process enables users to transform the received data from the device and establish the necessary values for transmission to Commander.

Device Setup

To configure the device, navigate to ‘Settings Communication’ and then select ‘MQTT’. Proceed by following the steps outlined below, and make the specified changes as indicated in Figures 1, 2, 3, and 4. For the device’s MQTT settings within the ‘General’ tab:

  1. Enter the specific broker address provided by your MQTT configuration.
  2. Enter the port:
    • If TLS (Transport Layer Security) is disabled, set the port to 1883.
    • If TLS is enabled, configure the port as 8883.
  3. Assign a unique client ID, similar to the Device serial number, to facilitate identification within the MQTT network.

Generic Driver

Figure 1 - General Tab

On the ‘User Credentials’ tab:

  1. Input the designated username and password that will be used for establishing a connection to the broker. Ensure that these credentials align with the requirements of your MQTT broker for secure and authenticated access.

Generic Driver

Figure 2 - User Credentials Tab

On the ‘SSL/TLS’ tab:

  1. If SSL/TLS is to be enabled, activate it on this page to enhance the security of the connection.
  2. Upload the Certificate Authority (CA), certificate (Cert), and key files. These files play a crucial role in establishing a secure and encrypted connection to the MQTT broker. Ensure that the uploaded files are valid and meet the security requirements of your environment.

Generic Driver

Figure 3 - SSL/TLS Tab

On the ‘Topic and Parameter Selection’ tab:

  1. Specify the topic path to which the device should publish its data. This is the MQTT topic where the information will be transmitted.
  2. Choose the desired Quality-of-Service level to be used for message delivery.
  3. Indicate whether messages should be retained or not. Retained messages persist on the broker and are sent to new subscribers when they connect.
  4. Select the interval at which the device should publish data to the specified topic.
  5. Choose the properties for which the device should send data. This involves specifying the parameters or data fields that will be included in the published messages. Configure these settings to tailor the device’s MQTT communication to your specific requirements on the Topic and Parameter Selection tab.

Generic Driver

Figure 4 - Topic and Parameter Selection Tab

After making the necessary configurations on the various tabs, ensure to save the settings and initiate a reboot of the device to apply the changes.

Example Packet

{
  "timestamp": 1686321300,
  "gateway": {
    "name": "AXM-WEB2",
    "model": "AXM-WEB2",
    "serial": "AN21113418"
  },
  "device": {
    "name": "IoT.nxt-Test",
    "model": "Acuvim-II",
    "serial": "AHB53020376",
    "online": true,
    "readings": [
      {
        "param": "V1",
        "value": "0.000",
        "unit": "V"
      },
      {
        "param": "V2",
        "value": "0.000",
        "unit": "V"
      },
      {
        "param": "V3",
        "value": "0.000",
        "unit": "V"
      },
      {
        "param": "Vnavg_V",
        "value": "0.000",
        "unit": "V"
      },
      etc...
    ]
  }
}

Driver Config Setup

To set up a Driver Config, follow the steps below:

  1. Deploy an instance of the Generic Driver interface.
  2. Set up the Device Options with the following settings:
{
  "Devices": {
    "HencoMQTTDevice": {
      "Enabled": true,
      "ActionDelay": 60000,
      "DeviceType": "Generic",
      "GatewayId": "DEFAULT GATEWAY ID",
      "GroupName": "DEFAULT GROUP NAME",
      "DataSource": {
        "DataSourceType": "Mqtt",
        "Host": "BROKER URL HERE",
        "PortNo": 8883 (or 1883 if UseTls = false),
        "UseTls": true,
        "UserName": "USERNAME",
        "Password": "PASSWORD",
        "Topics": {
          "Telemetry": "TOPIC TO SUBSCRIBE ON"
        }
      },
      "Filters": [
        {
          "FilterType": "CSharpScript",
          "Order": 1,
          "ProjectId": ENTER A PROJECT NAME HERE (example: "MQTT"),
          "InstanceType": "Singleton",
          "PropertyMaps": {
            "LoadType": {
              "DataType": "String"
            },
            //ADD MORE PROPERTIES WITH THEIR DATATYPES HERE.
          }
        }
      ]
    }
  }
}

In the code sample above, include any options necessary in the //ADD MORE PROPERTIES WITH THEIR DATATYPES HERE section. The properties specified in the PropertyMaps are the only properties that will have their values sent to Commander.

NOTE
Full descriptions for each property of the ‘Example Config’ are outlined in this link C-Sharp Script Editor.

C-Sharp Script Setup

To enable the processing of the payload, you can:

  1. Create a C# script file (.cs) with the necessary logic, and upload it to the Generic Driver. Below is a basic example structure for such a script file.
  2. Upload the following script to the Generic Driver, as a .cs file:
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using DeviceInfo = IoTnxt.Raptor.Device.Core.DeviceInfo;

namespace IoTnxt.Raptor.Generic.Filter;

/// <summary>
/// Script supports Acuvim II with Meter Firmware: 	v6.11 and WEB2 Module Firmware: v1.23 for the MQTT data source.
/// </summary>
public class PayloadExecutor : IPayloadExecutor
{
    private readonly ILogger _logger;

    /// <summary>
    /// </summary>
    /// <param name="logger"></param>
    public PayloadExecutor(ILogger<PayloadExecutor> logger)
    {
        _logger = logger;
    }

    /// <summary>
    /// Executes the filter to process the payload
    /// </summary>
    /// <param name="payload">The payload to process</param>
    /// <param name="cancellationToken">Cancellation token</param>
    /// <returns>A Task</returns>
    public Task ExecuteAsync(IPayload payload, CancellationToken cancellationToken)
    {
        //_logger.LogDebug($"Payload size = {payload.Data.Length}");
        var packet = payload.DeserializeAsJson<DataPacketModel>();

        var deviceInfo = new DeviceInfo
        {
            GatewayId = packet.Gateway.Serial,
            GroupName = packet.Device.Serial,
            DeviceType = packet.Device.Model,
            DeviceName = packet.Device.Name
        };

        if (deviceInfo.GatewayId == null || deviceInfo.GroupName == null || deviceInfo.DeviceType == null ||
            deviceInfo.DeviceName == null)
        {
            _logger.LogError($"Invalid device info: Skipping packet");
            return Task.CompletedTask;
        }

        var dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(packet.Timestamp);

        foreach (var reading in packet.Device.Readings)
        {
            if (payload.PropertyMaps != null && payload.PropertyMaps.Any())
            {
                if (payload.PropertyMaps.ContainsKey(reading.Param))
                    payload.SetValue(reading.Param, reading.Value, dateTimeOffset.UtcDateTime, deviceInfo);
            }
            else
                payload.SetValue(reading.Param, reading.Value, dateTimeOffset.UtcDateTime, deviceInfo);
        }

        return Task.CompletedTask;
    }
}

/// <summary>
/// </summary>
public class DataPacketModel
{
    /// <summary>
    /// </summary>
    public long Timestamp { get; set; }

    /// <summary>
    /// </summary>
    public GatewayModel Gateway { get; set; }

    /// <summary>
    /// </summary>
    public DeviceModel Device { get; set; }
}

/// <summary>
/// </summary>
public class GatewayModel
{
    /// <summary>
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// </summary>
    public string Model { get; set; }

    /// <summary>
    /// </summary>
    public string Serial { get; set; }
}

/// <summary>
/// </summary>
public class DeviceModel
{
    /// <summary>
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// </summary>
    public string Model { get; set; }

    /// <summary>
    /// </summary>
    public string Serial { get; set; }

    /// <summary>
    /// </summary>
    public bool Online { get; set; }

    /// <summary>
    /// </summary>
    public ReadingModel[] Readings { get; set; }
}

/// <summary>
/// </summary>
public class ReadingModel
{
    /// <summary>
    /// </summary>
    public string Param { get; set; }

    /// <summary>
    /// </summary>
    public string Value { get; set; }

    /// <summary>
    /// </summary>
    public string Unit { get; set; }
}