Using compute plugins

Compute plugins are used similarly to input plugins and output plugins. First, you need to specify your plugin details in appsettings.xml. Than you use the EventDefinition.xml to define the data routing. For more details see the following page.

Loading your compute plugin

In your appsettings.xml configuration file, add a section ComputePlugins which might contain the loading configuration for one or several compute plugins. Refer to the following example appsettings.xml.

<?xml version="1.0" encoding="utf-8"?>
<AgentConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                    xsi:schemaLocation="https://senseforce.io/ configurations/Schemas/appsettings.xsd" >
  <EgressPlugins>
    <EgressPlugin name="Mqtt_senseforce">
      <FilePath>$(RuntimePath)Plugins/Egress/MqttNet/MqttNetPlugin.dll</FilePath>
      <TypeName>Senseforce.Agent.Extensibility.Egress.Plugins.MqttNet.MqttHandlerTpl</TypeName>
      <ConfigurationFile>$(LunaAppDataPath)configurations/OutputPlugins/MqttNet/MqttSettings.xml</ConfigurationFile>
    </EgressPlugin>
  </EgressPlugins>
  
  <IngressPlugins>
    <IngressPlugin name="HelloWorld">
      <FilePath>$(RuntimePath)Plugins/Ingress/HelloWorld/HelloWorld.dll</FilePath>
      <TypeName>Senseforce.Agent.Extensibility.Ingress.Plugins.HelloWorld.HelloWorldHandler</TypeName>
      <ConfigurationFile>$(LunaAppDataPath)configurations/InputPlugins/HelloWorld/HelloWorldSettings.xml</ConfigurationFile>
    </IngressPlugin>
  </IngressPlugins>
  
  <ComputePlugins>
    <ComputePlugin name="Compute_demo">
      <FilePath>$(RuntimePath)Plugins/[PathToYourPluginDll]\HelloWorldCompute.dll</FilePath>
      <TypeName>Senseforce.Agent.Extensibility.Compute.Plugins.HelloWorld.HelloWorldComputeHandler</TypeName>
      <ConfigurationFile>$(LunaAppDataPath)configurations/ComputePlugins/HelloWorldCompute/DemoSettings.xml</ConfigurationFile>
    </ComputePlugin>
  </ComputePlugins>

  
  <!-- Mode: Live or offline -->
  <Mode>Live</Mode>
  
  <!-- Where to find the data routing definition file -->
  <Mappings>
    <FilePath>$(LunaAppDataPath)configurations</FilePath>
    <FileName>EventDefinition.xml</FileName>
  </Mappings>
  
  <!-- Where to put the log file and which log level to set -->
  <Logger>
    <FilePath>$(LunaAppDataPath)Logs</FilePath>
    <FileName>agent.log</FileName>
    <!--LogLevel: Debug,Information,Warning,Error,Critical,None-->
    <LogLevel>Information</LogLevel>
  </Logger>
</AgentConfiguration>

Please refer to lines 20 to 26 for how to load a compute plugin. The other sections are described in detail here: https://manual.senseforce.io/manual/senseforce-edge/edge-configuration/which-plugins-to-load-appsettings.xml. As a summary, we see that we are loading three plugins. One output plugin, one input plugin and one compute plugin.

  • Output Plugin: Mqtt-Plugin with the name “Mqtt_senseforce” (see line 5 to 8)

  • Input Plugin: HelloWorld-Plugin with the name “HelloWorld” (see line 13 to 17)

  • Compute Plugin: HelloWorldCompute-Plugin with the name “Compute_demo” (see line 21 to 25)

The compute plugin configurations are:

The plugin attribute "name" is reserved for future use and does not provide any further service.

  • FilePath (Line 21): This setting needs to point to your main plugin binary. You might use the Senseforce Edge relative path specifiers as described in the section "Path helpers" below or you might use an absolute file path.

  • TypeName (Line 22): Fully qualified class-name of the plugins entrypoint. It consists of [namespace].[classname]. Eg. if your plugin C# class is HelloWorldComputeHandler in the namespace Senseforce.Agent.Extensibility.Compute.Plugins.HelloWorld, your typename resolves to Senseforce.Agent.Extensibility.Compute.Plugins.HelloWorld.HelloWorldComputeHandler.

TypeName can be any combination of your[namespace].[classname]. It's not necessary, that your TypeName s in the Senseforce.Agent. - Namespace

  • ConfigurationFile (Line 23): Each plugin might (optionally) have a configuration file. You might want to refer to this configuration file in the appsettings.xml as this path is provided as parameter of the compute plugins constructor - allowing to load the configuration file during plugin setup. You might use the Senseforce Edge relative path specifiers as described in the section "Path helpers" below or you might use an absolute file path. This setting is optional and might be empty.

Summary

Execute the following steps to load a compute plugin with your Senseforce Edge:

  1. Add ComputePlugins - section to your appsettings.xml (see line 20 to 26).

  2. Add one or several ComputePlugin - sections (see line 21 to 25). Each ComputePlugin needs to have:

    1. FilePath (Path to where to find the plugin)

    2. TypeName (Fully qualified class-name of your plugin implementation)

    3. Optional: ConfigurationFile (File path to the plugin’s own configuration file. This path will be provided as parameter in the plugin constructor).

Path helpers

For the FileName as well as the ConfigurationFile you need to set either an absolute path, or use the Senseforce edge relative path modifiers. Two modifiers are available:

  • $(RuntimePath): This path points to the location where your main Edge binaries are installed. For example, if your Edge is installed at "C:/ProgramFiles/Edge/Luna.exe", and you set your FileName to $(RuntimePath)Plugins/MyDll.dll, your path will resolve to C:/ProgramFiles/Edge/Plugins/MyDll.dll.

  • $(LunaAppDataPath): This path points to the location where your edge configurations are located. If you run your Edge as console application, the configuration location is [yourEdgeInstallationFolder]/configs. As an example, if you set your ConfigurationFile setting to $(LunaAppDataPath)configurations/MyPlugin/config.xml, your path will resolve to [yourEdgeInstallationFolder]/configs/configurations/MyPlugin/config.xml. If you run your Edge as windows service, the default location of your configurations is "C:/ProgramDate/Senseforce/Luna Data/[YourServiceName_ID]/configs". Now our example from before resolves to C:/ProgramDate/Senseforce/Luna Data/[YourServiceName_ID]/configs/configurations/MyPlugin/config.xml.

Do not add a slash or backslash ("/", "\") behind your relative path modifier.

Ordinary relative paths without the relative path modifiers are not supported.

Routing data to and from compute plugins

For a general understanding about the Senseforce data routing engine visit the following manual page.

The Senseforce data routing architecture

To deepen the understanding of Senseforce Edge data routing, the high-level architecture of the Senseforce Edge is described here.

The main element of the Edge data routing is a central stream processor and multiplexer. The output messages of each input plugin are routed to the stream processor. Furthermore, output plugins can subscribe to one or several messages of the stream processor.

With the compute plugins now being available, compute plugins can also subscribe to one or several messages of the stream processor. Furthermore, all results of compute plugins are redirected back to the stream processor, allowing either other compute plugins or output plugins to consume these messages via the stream processor infrastructure.

How to subscribe for messages?

Each message coming to the Stream processor needs to have an IngressKey data-point. This data-point is used to determine the "type" of this message. Output plugins or compute plugins can subscribe to messages by referring to the IngressKey. Please note, that InputPlugins and ComputePlugins can create messages with various IngressKey- they are not limited to a single message-type. However, it is mentioned that for most use-cases a single IngressKey per plugin is sufficient.

Below you find a rather advanced example, showing how several input plugins, a compute plugin and several output plugins interact.

  • Input Plugin 1 creates messages with IngressKey = msg1. Output Plugin 1 is subscribed to messages with this IngressKey. This means, all messages from Input Plugin 1 are directly sent to Output Plugin 1.

  • Input Plugin 2 creates two messages, one with IngressKey = msg2 and one with IngressKey = msg3.

    • Both messages are sent to the Compute Plugin 1, as the plugin is subscribed to both IngressKeys.

    • Messages with IngressKey = msg3 are at the same time sent to Output Plugin 2.

  • Compute Plugin 1 then creates messages with an IngressKey = msg4, which is than sent to Output Plugin 2, as this plugin is subscribed to IngressKey = msg4. A real-life example might be, that the compute plugin combines values from both msg3 and msg2 and creates one combined data stream msg4.

Configuring the data routing

Similar to data routing between Input- and Output-plugins, use the EventDefinition.xml configuration file to define, which messages are routed to which plugin.

See the Senseforce manual for Edge data routing to get a basic understanding of the data rouging mechanisms: Edge Data Routing (EventDefinition.xml) - Senseforce 2.0 Manual

To understand, how compute plugin data routing works, let’s consider the following sample file. In the example description, it is referred to the name of plugins. The plugin’s names are defined in the appsettings.xml file where you load the plugins. See the first chapter in this manual for more details.

<?xml version="1.0" encoding="utf-8" ?>
<MappingConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="https://senseforce.io/ Schemas/mappings.xsd" >
  <Mappings>
    <Mapping>
      <TargetPlugins>
        <TargetPlugin>Compute_demo</TargetPlugin>
        <TargetPlugin>Mqtt_senseforce</TargetPlugin>
      </TargetPlugins>
      <IngressKey>Hello</IngressKey>
      <Event>
        <Timestamp>$(Timestamp)</Timestamp>
        <Type>MDE10</Type>
        <Id>$(GUID)</Id>
        <Datas>
          <Data name="Id">$(Id)</Data>
          <Data name="SawArea">$(SawArea)</Data>
          <Data name="CutLength">$(CutLength)</Data>
          <Data name="MachineNumber">$(MachineNumber)</Data>
          <!-- you can enter text before or after your variable, as demonstrated below -->
          <Data name="Material">my_$(Material)_in</Data>
        </Datas>
      </Event>
    </Mapping>    
    <Mapping>
      <TargetPlugins>
        <TargetPlugin>Mqtt_senseforce</TargetPlugin>
      </TargetPlugins>
      <IngressKey>Compute_demo_key</IngressKey>
      <Event>
        <Timestamp>$(Timestamp)</Timestamp>
        <Type>ComputedType</Type>
        <Id>$(GUID)</Id>
        <Datas>
          <Data name="MyMeasurementCompute">$(Measurement)</Data>
        </Datas>
      </Event>
    </Mapping>  
  </Mappings>
</MappingConfig>
  • This example defines two data mappings (see line 5 to 24 for the first and line 25 to 38 for the second mapping).

  • Each mapping actually represents one subscription in the sketch above (see sketch “Edge data mapping” above). (Note: Input plugins and compute plugin outputs are automatically connected to the Stream processor. Therefore, you only need to define the subscription)

  • The first mapping is used to to create subscriptions for Plugins with the name “Mqtt_senseforce” and “Compute_demo” (see lines 6 to 8 ). The subscription is created for messages with the “IngressKey = Hello” (see line 10). Meaning, all messages which arrive at the stream processor with the “IngressKey = Hello” are redirected to both, “Mqtt_senseforce” and “Compute_demo”.

  • The second mapping creates a subscription again for the Plugin “Mqtt_senseforce”, for all messages with “IngressKey = Compute_demo_key”. Meaning, all messages arriving at the stream processor with the IngressKey = Compute_demo_key are redirected to “Mqtt_senseforce”.

  • The lines in the Event - xml-tags are defining how the message looks like. This is the same for “normal” input plugins as well as compute plugins and is described here: Edge Data Routing (EventDefinition.xml) - Senseforce 2.0 Manual

Combining both examples (EventDefinition.xml and appsettings.xml) provides the following Edge situation:

  • We load the following plugins (see appsettings.xml)

    • Output Plugin: Mqtt-Plugin with the name “Mqtt_senseforce” (see line 6 to 10)

    • Input Plugin: HelloWorld-Plugin with the name “HelloWorld” (see line 20 to 24)

    • Compute Plugin: HelloWorldCompute-Plugin with the name “Compute_demo” (see line 13 to 17)

  • The compute plugin subscribes to all messages with IngressKey = Hello.

  • The output plugin subscribes to all messages with IngressKey = Hello and IngressKey = Compute_demo_key.

  • Assuming, that the Input plugin creates messages with IngressKey = Hello and the compute plugin generates messages with IngressKey = Compute_demo_key, the following architecture is configured:

For this example to work, the Input plugin “HelloWorld” needs to create messages with an IngressKey = Hello. And the “Compute_demo” - plugin needs to create messages with IngressKey = Compute_demo_key.

Last updated