By the end of the configuration tutorial you should feel comfortable using the SDK Configuration capabilities and have an understanding of the dynamic nature of configuration which is an integral part for making your application configurable and modifiable - even while the application is running.
Before you begin
You should have completed the Getting Started tutorial to integrate the Agora.Edge SDK into your project before starting and have a project ready to use with the tutorial.
The default name for your application is the Entry Assembly Name. This Name can be overridden using IIoT Edge App Configuration, which is very useful when configuring the application to interact with other applications.
The Application Name (Config["Name"]) is used as the NATS Client identifier when routing messages.
Copy the following code into a Program.cs file.
using static Agora.SDK;
public class Program
{
public static void Main(string[] args)
{
"Starting".LogHeading();
$"Hello from {Config["Name"]}!".LogInfo();
"Stopping".LogHeading();
}
}Copy the following code into a program.py file.
from agoraiot import config, logger
logger.heading("Starting")
logger.info(f"Hello from {config['Name']}!")
logger.heading("Stopping")Running the application will produce an output similar to:
-------------------------------------------------------------------------------
(33) Starting
-------------------------------------------------------------------------------
I(36) - Hello from Module!
-------------------------------------------------------------------------------
(37) Stopping
-------------------------------------------------------------------------------To override the name of the application, add a json file to the project called AEA.json.
To set the Name, open the AEA.json file and add the following:
AEA.jsonconfiguration file:
{
"Name": "MyApp"
}An AEA.json file can contain nested settings.
Copy the contents below into your AEA.json file of your application.
{
"Name": "MyApp",
"MyApp": {
"Setting1": "Value",
"Setting2": ["An", "Array", "of", "Values"]
}
}The following codes shows how to access the settings.
Program.cs:
using System.Text;
using static Agora.SDK;
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine($"The name of my app is `{Config["Name"]}'");
Console.WriteLine($"Setting1 = `{Config["MyApp:Setting1"]}'");
/* Accessing a setting with an array */
var settings = Config.GetSection("MyApp:Setting2").GetChildren().AsEnumerable();
Console.Write("Setting2 contains `");
foreach (var s in settings)
Console.Write(s.Value + ' ');
Console.WriteLine("'.");
}
}app.py:
from agoraiot import logger, config
print(f"The name of my app is '{config['Name']}'")
print(f"Setting 1 = '{config['MyApp:Setting1']}'")
settings = config['MyApp:Setting2']
print("Setting 2 contains '", end="")
for setting in settings:
print(setting + ' ', end="")
print("'.")Output:
The name of my app is `MyApp'
Setting1 = `Value'
Setting2 contains `An Array of Values '.The purpose of the runtime configuration via Redis is to allow configuration of the application once it is deployed as a container. Typically, the container would be installed on a Gateway, and AgoraOps would configure the application as needed for the problem being addressed by the application.
The SDK subscribes to a Redis key for runtime configuration. Updates to this key are read by the SDK at runtime and configuration is updated.
twin_properties/config/desired/<app-name>When running as a container, the SDK loads the configuration components in the following order:
- Default Settings: Set within the application.
- The Primary Config:
AEA.jsonof the application - Runtime config updated in Redis key
- Override Settings: Set within the application.
To see how these work together, perform the following steps:
- Update the Redis key above with a new
AEA.jsonwith the following contents and run the application
{
"MyApp": {
"Setting1": "New Value for Setting 1"
}
}- Using the same python code from the pervious tutorial go to the folder.
- Update the Redis key above with a new
AEA.jsonwith the following contents and run the application.
{
"MyApp": {
"Setting1": "New Value for Setting 1"
}
}Output:
The name of my app is `MyApp'
Setting1 = `New Value for Setting 1'
Setting2 contains `An Array of Values '.Settings (key names) are case insensitive.
For Python SDK, the use of a switch map is required.
While your application runs at the edge, it is likely that you will want to make it respond to configuration changes. You can do so by:
- Using an
Agora.ObservableSetting.
Both methods are illustrated as below:
AEA.json:
{
"Name": "ConfigurationTutorial",
"Author": "Original Author",
"Authors": [ "Author1", "Author2" ]
}Program.cs:
using static Agora.SDK;
public class Program
{
static public void Main()
{
"Starting".LogHeading();
WriteAuthor();
// Method 1
//Config.GetReloadToken().RegisterChangeCallback(InvokeChange, null);
//"If you modify any setting you will get a ReloadTokenChange".Cout();
// Method 2
//ObservableSetting.Get("Author").PropertyChanged += AuthorObservableSettingChanged;
//$"If you modify the 'Author' setting, you will get an ObservableSetting notifications.".Cout();
Console.ReadLine();
"Stopping".LogHeading();
}
private static void WriteAuthor() => $"Author is set to `{Config["Author"]}`".Cout();
private static void AuthorObservableSettingChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
{
WriteAuthor();
}
private static void InvokeChange(object o)
{
"Configuration Reloaded:".Cout();
WriteAuthor();
// You must re-register the change callback as the Configuration.ReloadToken has changed
Config.GetReloadToken().RegisterChangeCallback(InvokeChange, null);
}
}from agoraiot import *
def handle_config_change():
print( "Configuration Reloaded" )
write_author()
def author_setting_change(payload):
write_author()
def write_author():
print( f"Author is set to `{config["Author"]}`")
logger.heading("Starting")
write_author()
# Method 1
# config.observer_config(handle_config_change)
# print("If you modify any setting you will get a ReloadTokenChange")
# Method 2
# config.observe("Author", author_setting_change)
# print("If you modify the 'Author' setting, you will get a notification)
input("Waiting")
logger.heading("Stopping")Both methods of handling configuration change may be used, even at the same time. If you uncomment the lines after each // Method you can see what happens when you modify settings using the config/AEA.json file and the key-per-files such as config/keys/authors or config/keys/authors__0.
Sometimes it is necessary to understand the full configuration to assist in troubleshooting issues. Below shows how to use the SDK to write the configuration to logger as Info.
logger.info( json.dumps(config.get_dict(), indent=4) )