While the Rule Engine handles standard automation tasks, some scenarios require complex calculation, state management, or custom protocol parsing. For these cases, Proxus allows you to deploy compiled C# Functions directly to the Edge Gateway.
Deployment & Scope
Unlike Devices which are bound to a single Gateway, Functions can be deployed to multiple Gateways simultaneously.
- Specific Assignment: You can select specific Edge Gateways to run the function.
- Default (SYSTEM): When creating a new function, the SYSTEM gateway is selected automatically by default. You can add more gateways or change this assignment as needed.
Function Architecture
User functions are independent C# classes that inherit from the Proxus.SDK.BaseFunctions.FunctionBase class. They run inside a sandboxed environment on the Gateway, ensuring that a crashing script does not take down the entire system.
Basic Structure
Every function must override the OnMessageReceive method. This method is triggered asynchronously for every data packet passing through the Gateway.
using System;
using System.Threading.Tasks;
using Proxus.SDK.BaseFunctions;
using Proxus.Common.Messages;
public class MyCustomLogic : FunctionBase
{
// Called once when the function starts
protected override void OnStarted()
{
LogInformation("MyCustomLogic function started.");
// Optional: Set up a recurring task
ExecuteScheduledTask(TimeSpan.FromSeconds(30), () =>
{
LogInformation("Periodic check running...");
});
}
// Called for every telemetry packet
protected override void OnMessageReceive(FunctionContext ctx)
{
// 1. Check if the message is TransportData
if (ctx.Message is TransportData data)
{
// 2. Filter: Only process specific topics or devices
if (ctx.Topic != "Gen_01")
{
return;
}
// 3. Extract Value (Helper method in your logic or manual parsing)
// Note: TransportData payload is a list of key-value pairs
var tempMetric = data.Payload.FirstOrDefault(p => p.Key == "Temperature");
if (tempMetric != null && double.TryParse(tempMetric.Value, out double temp))
{
// 4. Logic: Calculate efficiency
double efficiency = (temp / 120.0) * 100;
// 5. Action: Save result back to pipeline
if (efficiency < 50)
{
LogWarning($"Low Efficiency Detected: {efficiency:F2}%");
// Create new data packet
var resultData = new TransportData();
resultData.MetaData.Add(new MetaData { Key = "DeviceName", Value = "Gen_01_Calc" });
resultData.Payload.Add(new Payload
{
Key = "Efficiency",
Value = efficiency.ToString(),
Type = "Double"
});
// Send back to system
Save(resultData);
}
}
}
}
}SDK Capabilities
The FunctionBase class provides powerful methods to interact with the runtime.
Logging
Use strongly-typed logging methods. These logs appear in the centralized System Logs.
| Method | Description |
|---|---|
LogInformation(string) | Standard info log. |
LogWarning(string) | Warning log (yellow). |
LogError(string) | Error log (red). |
LogDebug(string) | Debug log (visible only when debug mode is enabled). |
Data Operations
| Method | Description |
|---|---|
Save(TransportData) | Injects a new data point into the system pipeline or saves directly to DB. |
SendNotification(channel, msg) | Triggers a notification via a configured channel (e.g., "Email", "Slack"). |
UpdateDeviceStatus(id, status) | Updates the status of a specific device in the system registry. |
Advanced Features
1. Caching & State
Functions are stateful. You can use the built-in thread-safe Cache dictionary or class-level variables to maintain state between messages.
// Enable automatic cache cleanup (removes entries older than 1 hour)
EnableCacheWithExpirationTime = TimeSpan.FromHours(1);
// Add/Update cache
Cache.AddOrUpdate(DateTime.UtcNow, data, (k, v) => data);2. Scheduling
You can schedule background tasks without blocking the main message loop.
// Run every 10 seconds
ExecuteScheduledTask(TimeSpan.FromSeconds(10), () =>
{
// Perform periodic calculation or cleanup
});3. MQTT Client
The SDK includes a managed MQTT client for communicating with external brokers directly from your script.
// Publish to an external broker
PublishMqttMessage("external/topic", "payload");
// Subscribe to external topic (handled in OnMessageReceive)
SubscribeToMqttTopic("external/command");Best Practices
- Non-Blocking:
OnMessageReceiveshould be fast. For long-running operations, useTask.Runor scheduled tasks. - Exception Handling: Unhandled exceptions are caught by the runtime, but frequent crashes may cause the function to be automatically undeployed (Threshold: 10 exceptions).
- Dependencies: Stick to standard .NET libraries (
System,System.Linq,System.Text.Json). External NuGet packages must be pre-installed on the Gateway.