TypeEdge is a strongly-typed development experience for Azure IoT Edge.
Перейти к файлу
Spyros Garyfallos 1e26a5147d docker support 2018-05-29 17:49:30 -07:00
Example docker support 2018-05-29 17:49:30 -07:00
Microsoft.Azure.IoT.TypeEdge docker support 2018-05-29 17:49:30 -07:00
Microsoft.Azure.IoT.TypeEdge.Host docker support 2018-05-29 17:49:30 -07:00
Microsoft.Azure.IoT.TypeEdge.Proxy docker support 2018-05-29 17:49:30 -07:00
Templates .vscode 2018-05-26 12:10:05 -07:00
images readme 2018-05-25 13:25:31 -07:00
.gitattributes Add .gitignore and .gitattributes. 2018-05-01 13:02:03 -07:00
.gitignore dotnet templates 2018-05-24 20:08:30 -07:00
LICENCE switched to internal nuget repo 2018-05-26 10:50:04 -07:00
Microsoft.Azure.IoT.TypeEdge-WithExample.sln dotnet templates 2018-05-24 20:08:30 -07:00
Microsoft.Azure.IoT.TypeEdge.sln nuget private repo & solutions separation 2018-05-21 13:37:11 -07:00
README.md .vscode 2018-05-26 12:10:05 -07:00
TypeEdgeRuntimeDepedencies.sln removed nuget & run in docker 2018-05-11 17:00:27 -07:00

README.md

Azure IoT TypeEdge

The Azure IoT TypeEdge introduces a strongly typed flavor of the inherently loosely coupled vanilla Azure IoT Edge.

Specifically:

  • It removes all configuration burden from an IoT Edge application, because configuration can be now automatically generated by code reflection.
  • Introduces compile time types checking across all modules
  • It adds the ability to emulate an IoT Edge device on the development environment, by running all components in memory, no containers involved
  • Simplifies the IoT Edge development down to an single F5 experience

Development Environment Setup

Important: If you just landed to this repo, make sure you setup your environment first before continuing

To setup your development environment for TypeEdge you will need to:

  1. Install Docker

  2. Install the latest .NET Core

    Important note: TypeEdge requires .NET Core 2.1.0-Preview2 and above, you can check your version by typing:

    dotnet --version
    

    As of 05/25/2018, the latest .NET Core release is this

  3. Install your favorite IDE (VS Code or VS 2017)

  4. Temporary step - private NuGet packages:

    Temporarily, and until GA, the required NuGet packages will be distributed through this private NuGet feed. After GA, these packages will be available in the www.nuget.org.

    Important note: Only MS FTE have access to this NuGet feed. To add the feed to your machine wide configuration just once. This is required because of the way dotnet templates at the moment work.

    To add the feed to your machine you will need your git credentials or a personal access token. TO get your git credentials, navigate to the VSTS repo and under "clone to your computer" section, click "Generate Git Credentials"

    Then, add your credentials to the command bellow and run it.

    nuget.exe sources Add -Name "private-typeedge-feed" -Source "https://msblox-03.pkgs.visualstudio.com/_packaging/private-nuget-feed/nuget/v3/index.json" -UserName USERNAME -Password PASSWORD
    

    You can download the latest nuget.exe from here

    You'll also need to add the RocksDB ARM repo:

    nuget.exe sources Add -Name "RocksDB ARM" -Source "https://www.myget.org/F/rocksdb-native-arm/api/v3/index.json"
    

These steps will get you ready to build your first TypeEdge application.


QuickStart

Here is the quickest way to get started with TypeEdge. This quick start will create an IoT Edge solution with two modules and run it in the IoT Edge emulator:

  1. Install the TypeEdge .NET Core solution template. Just type:

    dotnet new -i TypeEdge.Application::*
    

    Note: If you already installed the template and you want to update to a newer template version, you need to clear the dotnet http and template cache

    dotnet nuget locals http-cache --clear
    dotnet new --debug:reinit
    
  2. Copy the iothubowner connection string from your development Azure IoT Hub.

    The iothubowner is required because TypeEdge needs to provision a new device with the generated deployment configuration.

  3. Create a new IoT TypeEdge application:

    You can choose the TypeEdge application and modules names of this template. In the example bellow, the application is called Thermostat, and the two modules are called SensorModule and PreprocessorModule. These names will be used as class names, so Pascal casing is suggested.

    dotnet new typeedgeapp -n Thermostat -m1 SensorModule -m2 PreprocessorModule -cs "YOUR_IOTHUBOWNER_CONNECTION"
    
  4. Open in VS Code/Visual Studio 2017 and hit F5:

    cd Thermostat
    code .
    

    Note: you can build and run with no IDE, simply by executing the following

    dotnet build Thermostat
    cd Thermostat\Thermostat.Emulator
    dotnet run
    

    Note: You should now see the Edge Hub starting up.. .. and the messages flowing in ..

Congratulations! You just created your first TypeEdge application. Continue reading bellow to learn how to deploy this application to an IoT Device

How it works

TypeEdge for the moment only supports .NET Core C#. A TypeEdge application is a collection of TypeEdge Modules.

Module interface

TypeEdge leverages interfaces to define the structure and behavior of the modules. A typical example of a TypeEdge module definition is:

[TypeModule(Name = "SensorModule")]
public interface ISensorModule
{
   Output<SensorModuleOutput> Output { get; set; }
   ModuleTwin<SensorModuleTwin> Twin { get; set; }

   bool ResetModule(int sensorThreshold);
}

This module has a strongly typed output called Output and the messages type is SensorModuleOutput. Similarly, it has a module twin called Twin with type SensorModuleTwin

Note: TypeEdge allows you to define multiple twin properties to enable partial twin updates

Finally, this module has a method that can be invoked directly with the bellow method signature:

bool ResetModule(int sensorThreshold);

Module implementation

After describing the module behavior and structure with an interface, the next step is to implement this interface. This is effectively the code that will run in the TypeEdge module. Below is an implementation example of the above interface:

Click to see the full SensorModule implementation code
public class SensorModule : EdgeModule, ISensorModule
{
    public Output<SensorModuleOutput> Output { get; set; }
    public ModuleTwin<SensorModuleTwin> Twin { get; set; }

    public bool ResetModule(int sensorThreshold)
    {
        System.Console.WriteLine($"New sensor threshold:{sensorThreshold}");
        return true;
    }

    public override async Task<ExecutionResult> RunAsync()
    {
        while (true)
        {
            await Output.PublishAsync(
                new SensorModuleOutput() {
                    Data = new System.Random().NextDouble().ToString() });
            
            System.Threading.Thread.Sleep(1000);
        }
        return await base.RunAsync();
    }
} 

A **TypeEdge** module can override any of the virtual methods of the base class ``EdgeModule``. As demonstrated in the above example, the ``RunAsync`` method is used for implementing long running loops, typically useful for modules that read sensor values. Another virtual method is ``Configure``, which can be used to read custom module configuration during startup. Finally, the ``BuildSubscriptions`` is used to define handlers to incoming messages.

The complete EdgeModule definition is:

public abstract class EdgeModule
{
    public EdgeModule();

    public virtual void BuildSubscriptions();
    public virtual CreationResult Configure(IConfigurationRoot configuration);
    public virtual Task<ExecutionResult> RunAsync();
}

Module Subscriptions

TypeEdge uses the pub/sub pattern for all module I/O, except for the direct methods. This means that a module can subscribe to other module outputs, and publish messages to their inputs. To do this, a reference to the module interface definition is required. TypeEdge uses dependency injection to determine the referenced modules.

Bellow, is the constructor of the second module included in the application template called PreprocessorModule, that references the SensorModule via its interface.

public PreprocessorModule(ISensorModule proxy)
{
    this.proxy = proxy;
}

Using this proxy, the PreprocessorModule module can interact with the SensorModule:

Input.Subscribe(proxy.Output, async (msg) =>
{
    await Output.PublishAsync(new PreprocessorModuleOutput()
    {
        Data = msg.Data,
        Metadata = System.DateTime.UtcNow.ToShortTimeString()
    });
    return MessageResult.OK;
});

In this example, the PreprocessorModule's input called Input, subscribes to SensorModule's output, called Output, and defines a subscription handler, a delegate that will be called every time the SensorModule sends a messages through its Output . In this example, the PreprocessorModule will enrich the incoming message, and publish it to its output called Output . These subscriptions need to be declared in the BuildSubscriptions override.

The complete code of the template's PreprocessorModule is:

Click to see the full PreprocessorModule implementation code
public class PreprocessorModule : EdgeModule, IPreprocessorModule
{
    readonly ISensorModule proxy;

    public Output<PreprocessorModuleOutput> Output { get; set; }
    public Input<SensorModuleOutput> Input { get; set; }
    public ModuleTwin<PreprocessorModuleTwin> Twin { get; set; }

    public PreprocessorModule(ISensorModule proxy)
    {
        this.proxy = proxy;
    }

    public override void BuildSubscriptions()
    {
        Input.Subscribe(proxy.Output, async (msg) =>
        {
            await Output.PublishAsync(new PreprocessorModuleOutput()
            {
                Data = msg.Data,
                Metadata = System.DateTime.UtcNow.ToShortTimeString()
            });
            return MessageResult.OK;
        });
    }
}

Emulator

The emulator references the Runtime bits achieve the emulation. Under the hood, the emulator starts a console application that hosts the Edge Hub and all referenced modules. It will also provision a new Edge device to your designated IoT Hub (by the iothubowner connection string). This device will contain a fully functional deployment configuration, ready to be used to an actual device deployment.

To reference modules in an emulator application, both the interface and the implementation class of the module is required:

host.RegisterModule<ISensorModule, Modules.SensorModule>();

Finally, all subscriptions beyond to context of a single module can be defined here. For example:

host.Upstream.Subscribe(host.GetProxy<IPreprocessorModule>().Output);

Below is the complete template emulator code for reference.

Click to see the full emulator code
public static async Task Main(string[] args)
{
    //TODO: Set your IoT Hub iothubowner connection string in appsettings.json
    var configuration = new ConfigurationBuilder()
        .AddJsonFile("appsettings.json")
        .AddEnvironmentVariables()
        .AddCommandLine(args)
        .Build();

    var host = new TypeEdgeHost(configuration);

    //TODO: Register your TypeEdge Modules here
    host.RegisterModule<ISensorModule, Modules.SensorModule>();
    host.RegisterModule<IPreprocessorModule, Modules.PreprocessorModule>();

    //TODO: Define all cross-module subscriptions 
    host.Upstream.Subscribe(host.GetProxy<IPreprocessorModule>().Output);

    host.Build();

    await host.RunAsync();

    Console.WriteLine("Press <ENTER> to exit..");
    Console.ReadLine();
}

Proxy

TypeEdge adds functionality also for service application development (cloud side application). This template will create a Proxy project, useful for cloud side interaction with the TypeEdge application. It also leverages the interfaces as the way to create a strongly typed proxy client. The code to call a direct method of a TypeEdge module from the could side is literally one line:

ProxyFactory.GetModuleProxy<ISensorModule>().ResetModule(4);

Solution structure

Apparently, to reference module definition interfaces and to avoid coupling the module implementation code together, these interfaces need to be defined in a separate project that will be commonly shared across the solution, containing only the definition interfaces and the referenced types.

Device Deployment

[Coming soon]