... | ... | @@ -36,9 +36,13 @@ As the first task, we log something. |
|
|
|
|
|
```cs
|
|
|
ServerSettings serverSettings = ServerSettings.LoadSettingsFromFile("ServerSettings.xml");
|
|
|
string userPort = Environment.GetEnvironmentVariable("PORT") ?? "4000";
|
|
|
serverSettings.ServerConfig.Hosting.Urls = new List<string> { "http://+:" + userPort };
|
|
|
```
|
|
|
Here we parse the [`ServerSettings.xml` file](https://gitlab.hrz.tu-chemnitz.de/vws-demo/vws-spielwiese/-/blob/a7a78842b8d27ee4233c1f6648f2fc2b44e93f39/cs-module/ServerSettings.xml) for our server settings.
|
|
|
This file was part of the original example.
|
|
|
This file was part of the original example and as there are settings for some image stuff I ued it as base.
|
|
|
After the initial parsing we get the `PORT` environment variable or set it to 4000 if it doesn't exist.
|
|
|
The list of endpoints in the `ServerSettings.xml` will then be replaced by just our endpoint.
|
|
|
|
|
|
```cs
|
|
|
AssetAdministrationShellHttpServer server = new AssetAdministrationShellHttpServer(serverSettings);
|
... | ... | @@ -47,14 +51,16 @@ We create a new AAS HTTP server with the prior parsed settings. |
|
|
This is provided by `BaSyx.AAS.Server.Http`.
|
|
|
|
|
|
```cs
|
|
|
string userRegistry = Environment.GetEnvironmentVariable("REGISTRYPATH") ?? "http://registry.local:4000/registry";
|
|
|
|
|
|
RegistryClientSettings registryClientSettings = RegistryClientSettings.CreateSettings();
|
|
|
registryClientSettings.RegistryConfig.RegistryUrl = "http://registry.local:4000/registry";
|
|
|
registryClientSettings.RegistryConfig.RegistryUrl = userRegistry;
|
|
|
RegistryHttpClient registryHttpClient = new RegistryHttpClient(registryClientSettings);
|
|
|
```
|
|
|
We need a registry client to register and unregister our AAS at the remote registry.
|
|
|
The client also needs settings to know where to connect to.
|
|
|
We need a registry client to register and unregister our AAS descriptor at the remote registry.
|
|
|
The client also needs settings to know where to connect to, so we get the `REGISTRYPATH` environment variable or set another default value.
|
|
|
|
|
|
The settings could also be placed in an XML file and an [example is provided](https://github.com/eclipse-basyx/basyx-dotnet-components/blob/main/BaSyx.Registry.Client.Http/RegistryClientSettings.xml) when installing the `BaSyx.Registry.Client.Http` dependency (only shown in the project map, not uploaded to the repository).
|
|
|
These settings could also be placed in an XML file and an [example is provided](https://github.com/eclipse-basyx/basyx-dotnet-components/blob/main/BaSyx.Registry.Client.Http/RegistryClientSettings.xml) when installing the `BaSyx.Registry.Client.Http` dependency (only shown in the project map, not uploaded to the repository).
|
|
|
|
|
|
```cs
|
|
|
server.WebHostBuilder.UseNLog();
|
... | ... | @@ -126,14 +132,32 @@ Similar to before we use and define some namespaces. |
|
|
public class GreenLightAdministrationShellService : AssetAdministrationShellServiceProvider {
|
|
|
private readonly SubmodelServiceProvider lightSubmodelServiceProvider;
|
|
|
private static readonly ILogger logger = LogManager.GetCurrentClassLogger();
|
|
|
private string gpioPort = System.Environment.GetEnvironmentVariable("LED_PIN");
|
|
|
```
|
|
|
Start of the class definition and declaration of the `logger` and `lightSubodelServiceProvider` attributes.
|
|
|
Also the `LED_PIN` environment variable is fetched.
|
|
|
|
|
|
The class inherits the `AssetAdministrationShellServiceProvider` so lots of functionality used later is already given.
|
|
|
For example, we don't need to call `BuildAssetAdministrationShell` manually to create the AAS we want to host, but it is done for us automatically.
|
|
|
|
|
|
```cs
|
|
|
public GreenLightAdministrationShellService() {
|
|
|
if (gpioPort != null)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
Process exec = Process.Start("raspi-gpio", "set " + gpioPort + " op");
|
|
|
exec.WaitForExit();
|
|
|
exec = Process.Start("raspi-gpio", "set " + gpioPort + " dl");
|
|
|
exec.WaitForExit();
|
|
|
}
|
|
|
catch (System.Exception e)
|
|
|
{
|
|
|
logger.Error("Could not set output mode for gpio pin!");
|
|
|
logger.Error(e.Message);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
lightSubmodelServiceProvider = new SubmodelServiceProvider();
|
|
|
lightSubmodelServiceProvider.BindTo(AssetAdministrationShell.Submodels["lightSwitch"]);
|
|
|
|
... | ... | @@ -147,6 +171,28 @@ public GreenLightAdministrationShellService() { |
|
|
```
|
|
|
This is the constructor.
|
|
|
Lets go through it step by step:
|
|
|
|
|
|
```cs
|
|
|
if (gpioPort != null)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
Process exec = Process.Start("raspi-gpio", "set " + gpioPort + " op");
|
|
|
exec.WaitForExit();
|
|
|
exec = Process.Start("raspi-gpio", "set " + gpioPort + " dl");
|
|
|
exec.WaitForExit();
|
|
|
}
|
|
|
catch (System.Exception e)
|
|
|
{
|
|
|
logger.Error("Could not set output mode for gpio pin!");
|
|
|
logger.Error(e.Message);
|
|
|
gpioPort = null;
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
When a `LED_PIN` environment variable is provided we setup the pin in `gpioPort` by calling `raspi-gpio`.
|
|
|
In case anything bad happens we can't use this ``gpioPort` so we will set it `null` for later.
|
|
|
|
|
|
```cs
|
|
|
lightSubmodelServiceProvider = new SubmodelServiceProvider();
|
|
|
```
|
... | ... | @@ -188,22 +234,38 @@ As defined in the constructor it is called when a get operation for `lightState` |
|
|
```cs
|
|
|
private Task<OperationResult> LightActivateOperationHandler(IOperation operation, IOperationVariableSet inputArguments, IOperationVariableSet inoutputArguments, IOperationVariableSet outputArguments, CancellationToken cancellationToken) {
|
|
|
AssetAdministrationShell.Submodels["lightSwitch"].SubmodelElements["lightState"].Cast<IProperty>().Value = "on";
|
|
|
logger.Info("Green light was turned on!");
|
|
|
return new OperationResult(true);
|
|
|
|
|
|
bool result = true;
|
|
|
if (gpioPort != null)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
Process exec = Process.Start("raspi-gpio", "set " + gpioPort + " dl");
|
|
|
exec.WaitForExit();
|
|
|
logger.Info("Green light was turned on!");
|
|
|
} catch (System.Exception e)
|
|
|
{
|
|
|
logger.Error("Light should turn on, but raspi-gpio cannot be started!");
|
|
|
logger.Error(e.Message);
|
|
|
result = false;
|
|
|
}
|
|
|
} else
|
|
|
{
|
|
|
logger.Info("Green light was turned on!");
|
|
|
}
|
|
|
|
|
|
return new OperationResult(result);
|
|
|
}
|
|
|
```
|
|
|
Even if the function signature is enormous the function itself is quite simple.
|
|
|
When `activateLight` is called, we set `lightState` to `on` and log the event to the console.
|
|
|
As this should never fail we can return `true` as result.
|
|
|
When `activateLight` is called, we set `lightState` to `on`.
|
|
|
|
|
|
```cs
|
|
|
private Task<OperationResult> LightDeactivateOperationHandler(IOperation operation, IOperationVariableSet inputArguments, IOperationVariableSet inoutputArguments, IOperationVariableSet outputArguments, CancellationToken cancellationToken) {
|
|
|
AssetAdministrationShell.Submodels["lightSwitch"].SubmodelElements["lightState"].Cast<IProperty>().Value = "off";
|
|
|
logger.Info("Green light was turned off!");
|
|
|
return new OperationResult(true);
|
|
|
}
|
|
|
```
|
|
|
This basically is the same thing as above but for deactivating the light.
|
|
|
After that we will either call `raspi-gpio` but only if we have a `gpioPort` set or we will only log to the command line.
|
|
|
If something happens while calling `raspi-gpio` the result will be set to `false`.
|
|
|
|
|
|
In the end we return our operation result.
|
|
|
|
|
|
Basically the exact opposit is done in the function `LightDeactivateOperationHandler` so we will skip further explanation.
|
|
|
|
|
|
```cs
|
|
|
public override IAssetAdministrationShell BuildAssetAdministrationShell() {
|
... | ... | @@ -213,7 +275,7 @@ Here we create all the assets, submodules, properties, operations, etc. we want |
|
|
|
|
|
```cs
|
|
|
AssetAdministrationShell aas = new AssetAdministrationShell("greenLight_0", new Identifier("urn:de.olipar.basyx:cscomponent:greenLight_0", KeyType.IRI)) {
|
|
|
Description = new LangStringSet() { new LangString("en", "A demo dummy light AAS.") },
|
|
|
Description = new LangStringSet() { new LangString("en", "A demo light AAS.") },
|
|
|
|
|
|
Asset = new Asset("lightSwitchAsset", new Identifier("urn:de.olipar.basyx:cscomponent:greenLight_0", KeyType.IRI)) {
|
|
|
Description = new LangStringSet() { new LangString("en", "This is a demo light asset reference from the Asset Administration Shell") },
|
... | ... | |