Link Search Menu Expand Document

Sending Telemetry

Dec 7 2023 at 12:00 AM

  1. Sending Telemetry with a Receptor Device
    1. Telemetry Data
    2. Build a Telemetry Packet - Receptor Device
    3. Where to build the Telemetry Packet
    4. Telemetry Controller

Sending Telemetry with a Receptor Device

Once Devices have been registered and properties have been linked to endpoints in Commander’s Digital Twins, the user can configure telemetry packets. These packets link telemetry sent from the physical device to properties in the Digital Twin’s endpoints such as Current, Energy, PowerFactor, PowerStatus, Voltage, OutletTemperature.

Telemetry Data

Telemetry data received from physical devices provides information about what the instrument is measuring (actual values). For example, an energy meter’s telemetry data will be the energy levels the meter is measuring at any given time.

Build a Telemetry Packet - Receptor Device

Building a telemetry packet differs depending on the type of Device you are configuring. For Receptor Devices, the telemetry packet is configured in the Device file.

Where to build the Telemetry Packet

For Receptor Devices, the telemetry packet can be found just under the meta packet configuration in the Device file:

    while (!CancellationToken.IsCancellationRequested)
    {
        try
        {
            // Set the current property values
            cachedInfo.Properties["Prop1"].SetCurrentValue(123.456);

            cachedInfo.Properties["Prop2"].SetCurrentValue(789);

            // Send the telemetry
            await SendTelemetryAsync(cachedInfo);
        }
        catch (Exception ex)
        {
            LogError(ex, $"Exception sending Telemetry. {ex.Message}");
        }

        if (IsUnitTest) break;
        await Task.Delay(5_000, CancellationToken);
    }

In the code sample above:

  1. “Prop1” and “Prop2”: These properties will reflect the same properties that were defined and configured (with data types) in the meta package found above this section (in the same file). Properties that are defined in the section above need to correspond to the properties listed in this section.
  2. SendTelemetryAsync sends a telemetry request to the Collector service.

SetCurrentValue will read the value from the physical device and populate it in this section:

cachedInfo.Properties["Prop1"].SetCurrentValue(123.456);

cachedInfo.Properties["Prop2"].SetCurrentValue(789);

The values “123.456” and “789” are placeholder values. They will be populated with the correct values once the V-Raptor is connected to the physical device.

Telemetry Controller

For this use case, the telemetry packet will need to include a REST Controller so that it can retrieve data from the energy meter and send it to the Receptor Device. The user needs to take into account the following for this step:

  • The Telemetry Controller (the REST Controller) needs to be created as part of the telemetry packet.
  • The DevicesOptions.json file needs to be configured properly so that Device Manager can pick up the Device Name and execute this method for the correct Device.
  • A method called “ProcessDataAsync” will be called in the Device (the Receptor Device Interface in this use case) so that the data can be sent to the Device Interface.

For this use case, in the DevicesOptions.json file’s “Devices” section would include the following Device configuration with Device Name “kamstrup”:

"Devices" {
    "kamstrup" {
        "DeviceType": "<DeviceType>"
    }
}

In the code sample above, the Device’s name is “kamstrup”. The DeviceType will be the alias used for Device Binding.

The code sample below shows an example of a Telemetry Controller (a REST Controller) that retrieves the data from the physical device so that the Receptor Device (in this use case) can read the data:

using System;
using System.Net.Mime;
using System.Threading.Tasks; 
using IoTnxt.Raptor.DeviceManager; 
using IoTnxt.Raptor.Swagger; 
using Microsoft.AspNetCore.Http; 
using Microsoft.AspNetCore.Mvc; 
using Microsoft.Extensions.Logging; 
using Newtonsoft.Json;

namespace IoTnxt.Raptor.Device.Kamstrup.Controllers;

/// <summary>
/// Controller for telemetry callbacks
/// </summary>

public class TelemetryController: BaseController
{
    private readonly IDeviceManager _deviceManager;

    /// <inheritdoc /> 
    public TelemetryController(ILogger<TelemetryController> logger,
                IRateGaugeService rateGaugeService, IHttpContextAccessor accessor,
                IDeviceManager deviceManager,
                IServiceProvider serviceProvider)
        : base(logger, rateGaugeService, accessor, serviceProvider)
    {
        _deviceManager = deviceManager;
    }

    /// <summary> 
    /// Decrypts a Sigfox data string and extracts relevant information to send to Commander 
    /// </summary>
    /// <param name="deviceName">The name of the device that is to be used for the decryption and value extraction</param> 
    /// <param name="payload">Data packet received from Sigfox Server</param> 
    /// <returns>HTTPStatusCode</returns>

    [HttpPost("Add/{deviceName}")] 
    [Consumes(MediaTypeNames.Application.Json)] 
    [RequestExample(typeof(ISigfoxData), typeof(SigfoxValueObject))] 
    public Task Add(string deviceName, [FromBody]ISigfoxData payload)
    {
        return ExecuteWithLogTraceAsync(nameof(Add), $"EncryptionKey_{nameof(Add)}", 
            async () =>
            {
                if (_logger.IsEnabled(LogLevel.Trace))
                {
                    _logger.LogTrace($"Payload Received from Sigfox Server. [{deviceName}] Specified for Processing");

                    var json = JsonConvert.SerializeObject(payload);
                    _logger.LogTrace($"Received Payload: \n {json}");
                }

                var device = await _deviceManager.GetDeviceInstanceAsync(deviceName);
                if (device == null) throw new Exception($"Device [{deviceName}] does not exist!");

                if (device is not ISigfoxDataProcessor sigfoxDevice) throw new Exception("Device cannot handle payload!");

                await sigfoxDevice.ProcessDataAsync(payload);
                return Ok();
            });
    }
}
  1. HttpPost("Add/{deviceName}") - this is the REST endpoint for the API call. “deviceName” will be substituted by the Device Name provided in DevicesOptions.json (i.e. “kamstrup”). This endpoint is configured on the physical device to push data to the Driver.
  2. ProcessDataAsync will be called on the Device that was retrieved by Device Manager (using the deviceName to get the correct Device). This will process the data for the correct Device Interface.

In summary, the Telemetry Controller will:

  • Get the name of the Device (with deviceName).
  • Ask Device Manager to retrieve the Device with that deviceName from DevicesOptions.json.
  • Call a method (ProcessDataAsync) on that Device.