# Standard Edge Module Operations

In this tutorial, you will find information on how to accomplish basic tasks common to any edge module development.

Edge Module API

You can find general information about the Edge Module APIs here.

# Connecting to the EdgeBroker

The first thing any Edge module does is read the configuration & connect to the edgeBroker. All the properties required for such connection are passed as environment variables. Let's look at the output of the docker service inspect referenceModule command to see a sample list of the passed variables on an already running edge.

"Env": [
    "module_id=referenceModule",
    "mqtt_client_id=referenceModule",
    "mqtt_url=mqtt://edge-broker:1883",
    "mqtt_password_file=/run/secrets/referenceModule",
    "topics_model_in=modules/referenceModule/model/desired",
    "topics_model_out=modules/referenceModule/model/reported",
    "topics_methods_in=modules/referenceModule/methods/req",
    "topics_methods_out=modules/referenceModule/methods/res",
    "topics_messages_in=modules/referenceModule/messages/devicebound",
    "topics_messages_out=modules/referenceModule/messages/events",
    "topics_local_in=modules/local/referenceModule",
    "topics_local_out=modules/local",
    "topics_files_in=modules/referenceModule/files/notifications",
    "topics_files_out=modules/referenceModule/files/upload",
    "topics_lwt=modules/referenceModule/lwt",
    "object_id=208f12f0-e6ce-4d25-8728-dde6f2489cd1"
]

As we can see, there is a list of topics_*, an mqtt_password_file, mqtt_client_id, but what's the most important an mqtt_url. What do we need that for? Well, every edge module communicates with the "outer world" by sending and receiving MQTT messages. It doesn't matter if it is about sending a telemetry to the cloud or communicating with the other module. To send such a message, we need to first connect to the so called MQTT broker. To do this we need to know the URL of the broker (mqtt_url), the login (mqtt_client_id) and the password (mqtt_password_file). The first two we take directly from the variables and the password is written in plain text in the file located in mqtt_password_file. Let's check how these parts look in the code.

# Reading the configuration

The main class of each sample module in the provided projects inherit from the ModuleBase class. This is where you should look for the things that might be common to all modules.

The Configuration property definition in the ModuleBase class:

private IConfiguration _configuration;
protected IConfiguration Configuration
{
    get
    {
        if (_configuration == null)
        {
            //this environment variable is defined in the microsoft/dotnet:2.1-runtime-deps-alpine3.7 base image
            var envVariable = Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER");
            var isDocker = (envVariable ?? string.Empty).Equals(bool.TrueString, StringComparison.InvariantCultureIgnoreCase);
            Console.WriteLine($"Is module running as a Docker container: {isDocker}");

            _configuration = isDocker ? new EdgeConfiguration() : (IConfiguration)new ManualConfiguration();
        }
        return _configuration;
    }
}

The EdgeConfiguration initializer:

public EdgeConfiguration()
{
    ClientId = Env.GetEnvironmentVariable("mqtt_client_id");
    ServerUri = new Uri(Env.GetEnvironmentVariable("mqtt_url"));
    Username = Env.GetEnvironmentVariable("module_id");
    Password = File.ReadAllText(
        Env.GetEnvironmentVariable("mqtt_password_file"));
    MethodsInTopic = Env.GetEnvironmentVariable("topics_methods_in");
    MethodsOutTopic = Env.GetEnvironmentVariable("topics_methods_out");
    MessagesOutTopic = Env.GetEnvironmentVariable("topics_messages_out");
    ModelInTopic = Env.GetEnvironmentVariable("topics_model_in");
    CleanSession = true;
    ObjectId = Env.GetEnvironmentVariable("object_id");
    LocalInTopic = Env.GetEnvironmentVariable("topics_local_in");
    LocalOutTopic = Env.GetEnvironmentVariable("topics_local_out");
    FilesOutTopic = Env.GetEnvironmentVariable("topics_files_out");
    FilesInTopic = Env.GetEnvironmentVariable("topics_files_in");
}

# Connecting to the MQTT broker

Let's now see how we connect with the edgeBroker. In our examples we are using MQTTnet client which is easily downloadable as a nugget package.

private async void StartMessagingClient()
{
    _mqttClient = new MqttFactory().CreateManagedMqttClient();

    //Build options for the MQTT client based off of config values
    //If running as a Docker container on Ability Edge, the Edge runtime will supply these values to the container
    var options = new ManagedMqttClientOptionsBuilder()
        .WithClientOptions(
            new MQTTnet.Client.MqttClientOptionsBuilder()
                .WithClientId(this.Configuration.ClientId)
                .WithTcpServer(
                    this.Configuration.ServerUri.Host,
                    this.Configuration.ServerUri.Port)
                .WithCredentials(
                    this.Configuration.Username,
                    this.Configuration.Password)
                .WithKeepAlivePeriod(
                    TimeSpan.FromMilliseconds(
                    DEFAULT_KEEP_ALIVE_PERIOD_MS))
                .WithCleanSession(this.Configuration.CleanSession)
                .Build())
        .WithAutoReconnectDelay(
            TimeSpan.FromMilliseconds(DEFAULT_AUTO_RECONNECT_DELAY_MS))
        .Build();

    _mqttClient.ApplicationMessageReceived += OnApplicationMessageReceived;

    await _mqttClient.StartAsync(options);
    Console.WriteLine($"MQTT client created and started.");
}

# Summary

To deploy an edge module, you have to accomplish two tasks:

  1. Publish an image containing your module to the docker images repository
  2. Configure and run edge software installation scripts on your machine

The first step in more details would look like this:

  1. Compile the project
  2. Publish the project to dll
  3. Build a docker image and set your dll as an entry point
  4. Publish a docker image to a repository

And the second one like this:

  1. Prepare a type definition for your edge module in both abb.ability.device & abb.ability.configuration models
  2. Upload the type definitions through the type definition registry
  3. Configure the edge.env file to point to your edge type definition
  4. Run installation scripts

If you configured everything correctly, the edge should be up and running after few minutes. You can check the running services by executing docker service list from CLI.

Last updated: 9/6/2021, 1:25:50 PM
Feedback