Link Search Menu Expand Document

HTTPS REST API 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

The following document provides a guide for setting up a device and configuring it for the Post Channel using the Accuenergy portal, tailored for the Acuvim-II with AXM-WEB2 module. It focuses on a specific use case, employing the C-Sharp Script filter with the HTTPS REST API as the designated data source.
The user is required to specify a data source, in this instance, the HTTPS REST API, and subsequently define their filters using the (C-Sharp Script Editor). This combination provides a solution for transforming and transmitting data from the device to Commander.

Device Setup

On the device displayed in Figure 1 navigate to the ‘Settings’ menu, followed by ‘Communication’, and finally select ‘Post Channel’.

To configure the device, follow the outlined steps below, and make the specified changes as detailed in Figure 1:

  1. Enable the ‘Post Channel’ by selecting the corresponding checkbox.
  2. Choose HTTP/HTTPS as the ‘Post Method.’
  3. Disable the ‘Include HTTP Post Header (for JSON log file post only)’ setting.
  4. Enable the ‘Need Authorize’ option by selecting the checkbox.
  5. Choose the default method of authorization and input the API key as the token.
  6. In the HTTP/HTTPS URL field, enter the driver’s URL: https://URL_TO_SERVICE/api/telemetry/send/TARGET_DEVICE.
  7. For HTTPS, use port 443.
  8. Assign an ID to be used for the device.

By carefully following these steps and referencing Figure 1, you will successfully configure the device settings for the desired Post Channel setup.

Generic Driver

Figure 1 - Post Channel

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

This is an example packet of the JSON that the device sends. It sends a collection of timestamps, and then inside the values it would send the different endpoints that it measures.

{
  "timestamp": [
    "1604607360",
    "1604607420",
    "1604607480",
    "1604607540"
  ],
  "gateway": {
    "name": "AXM-WEB2",
    "model": "AXM-WEB2",
    "serial": "AN18070794"
  },
  "device": {
    "name": "",
    "model": "Acuvim-II",
    "serial": "AH15120356",
    "online": true,
    "readings": [
      {
        "param": "V1",
        "value": [
          "127.883",
          "128.08",
          "127.878",
          "127.737"
        ],
        "unit": "V"
      },
      {
        "param": "V2",
        "value": [
          "115.62",
          "115.794",
          "115.612",
          "115.486"
        ],
        "unit": "V"
      },
      {
        "param": "V3",
        "value": [
          "115.881",
          "116.058",
          "115.878",
          "115.748"
        ],
        "unit": "V"
      },
      {
        "param": "Vnavg_V",
        "value": [
          "119.795",
          "119.978",
          "119.789",
          "119.657"
        ],
        "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:

Example Config

{
  "Devices": {
    "HencoHTTPDevice": {
      "Enabled": true,
      "ActionDelay": 60000,
      "DeviceType": "Generic",
      "GatewayId": "DEFAULT GATEWAYID",
      "GroupName": "DEFAULT GROUPNAME",
      "DataSource": {
        "DataSourceType": "RestApi"
      },
      "Filters": [
        {
          "FilterType": "CSharpScript",
          "Order": 1,
          "ProjectId": "RestApi",
          "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.

Ensure the following settings are added to the IdentityClientOptions.json file in order to use an API key as a token on the device:

"EnableApiKeyDefaultServiceId": true,
"ApiKeyAuthorizationPrefix": "token"
Property NameDescription
EnableApiKeyDefaultServiceIdCommunicates to the Generic Driver that it is part of the HTTP call, and that it should use the ‘ServiceId’ as the default for the default driver. The driver’s name is as a Service ID.
ApiKeyAuthorizationPrefixAllows the user to specify the prefixes.

C-Sharp Script Setup

To facilitate 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 IoTnxt.Raptor.Device.Core;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace IoTnxt.Raptor.Generic.Filter;

/// <summary>
/// Script supports AcuRev 2110 with Meter Firmware: v1.15 and Module Firmware: v1.10 for REST API data source
/// Script supports Acuvim II with Meter Firmware: v6.11 and WEB2 Module Firmware: v1.23 for REST API 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("Starting Payload execution");
        var packet = payload.DeserializeAsJson<AccuVimDataPacketModel>();

        if (packet.Gateway != null && packet.Device != null)
        {
            _logger.LogDebug("Processing AccuVimDataPacketModel");
            ProcessAccuVimDataPacketModel(payload, packet);
        }
        else
        {
            var revPacket = payload.DeserializeAsJson<AccuRevDataPacketModel>();
            if (revPacket.DeviceModel != null && revPacket.DeviceName != null && revPacket.Readings != null)
            {
                _logger.LogDebug("Processing AccuRevDataPacketModel");
                ProcessAccuRevDataPacketModel(payload, revPacket);
            }
        }

        return Task.CompletedTask;
    }

    private void ProcessAccuVimDataPacketModel(IPayload payload, AccuVimDataPacketModel packet)
    {
        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;
        }

        for (var i = 0; i < packet.Timestamp.Length; i++)
        {
            var dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(packet.Timestamp[i]);

            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[i], dateTimeOffset.UtcDateTime, deviceInfo);
                }
                else
                    payload.SetValue(reading.Param, reading.Value[i], dateTimeOffset.UtcDateTime, deviceInfo);
            }
        }
    }

    private void ProcessAccuRevDataPacketModel(IPayload payload, AccuRevDataPacketModel packet)
    {
        var deviceInfo = new DeviceInfo
        {
            GatewayId = packet.DeviceName,
            DeviceType = packet.DeviceModel
        };

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

        for (var i = 0; i < packet.Timestamp.Length; i++)
        {
            var dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(packet.Timestamp[i]);

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

/// <summary>
/// </summary>
public class AccuVimDataPacketModel
{
    /// <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 AccuRevDataPacketModel
{
    /// <summary>
    /// </summary>
    public long[] Timestamp { get; set; }

    /// <summary>
    /// </summary>
    [JsonProperty("device_model")]
    public string DeviceModel { get; set; }

    /// <summary>
    /// </summary>
    [JsonProperty("device_name")]
    public string DeviceName { get; set; }

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

    /// <summary>
    /// </summary>
    public ReadingModel[] Readings { 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; }
}