Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / IoT / Raspberry-Pi

The Remote InterOperability Platform

4.67/5 (2 votes)
9 Sep 2022MIT8 min read 5.4K  
A guest OS for IoT devices, that can adapt easily to many different tasks
In this post, you will find a description of the architecture of RIO, a platform to implement IoT devices with complex features, already used in life saving technologies.

Introduction

The European Crisis Management Laboratory studies and develops technologies applied to the management of events with humanitarian impact.
Starting in 2014, several projects were related to early warning systems, we designed a technology that was able to fit all our needs. This led to the development of a guest operating system (i.e., relying on another OS) to operate remotely alerting or sensing devices.

With this, we implemented several devices mainly based on Raspberry Pi; but the main result is the definition of a composable infrastructure open to different hardware and communication means.
This is the first of a series of articles and will describe the architecture and the base implementation of RIO; while the following articles will illustrate in detail the most relevant implementations based on RIO.

The European Commission promotes the adoption of its open source projects, according to specific rules; therefore, the source code is only on its official repository and licensed under the MIT license.

This is the first of a series of articles, the following being:

  1. The RIO applied to the Inexpensive Device for Sea Level monitoring, IDSL
  2. The RIO implementation of alerting devices
  3. The RIO powers a GNSS based system to detect anomalous sea level behaviours
  4. The RIO can be everywhere (Python and nano framework portings)

Background

This series of articles aims at illustrating the usage of the software described in the related report RIO Remote InterOperability platform and the evolution of the last two years, together with the link to the source code public repository.

The author will also present some alternative implementations.

The development of the software spans across six years, which brought the evolution of .NET from the initial .NET Core to the present 6th version: the software evolved with that.

Description

The Remote InterOperability platform requires a software to manage the remotely deployed devices and an infrastructure to support it.The RIO software on the devices acts as a guest Operating System hosted by a native one to manage the features installed in the device. It is therefore able to implement remote sensors as well as alerting devices. In order to develop such a flexible software, .NET Core has been adopted, since this programming environment is available on many platforms including 32 and 64 bit Windows machines, Linux machines including small microcomputers and macOS machines. RIO needs an infrastructure to communicate with the devices; its description includes the network servers used to implement it, their configuration, the protocols and the formats adopted.

RIO Device Architecture

So far, RIO devices are based on a central processing unit provided by a Raspberry Pi and a variety of additional devices controlled by it. The Operating System chosen to run the Raspberry Pi is Raspbian, an evolution of the Debian distribution of Linux developed for this family of devices. This choice is not related to the programming platform, that is available also for other Operating Systems running on these devices (e.g., Windows IoT), but on the existing software and tested configuration developed for the IDSL project. The programming environment is based on .NET Core. The software progressed with the Core versions until 3.1. The specific features of the devices does not allow a complete migration to .NET 6; but many parts of the project are based on .NET Standard, therefore, much more portable.

.NET Core requires anyway that the ARM CPU of the Raspberry Pi is provided with a set of instructions available only from ARM 7 on: this requires to use Raspberry Pi 4, 3 or 2+ V1.1. Apart from considerations related to the specific platform, the RIO software can run on different devices and remains open to others, which will be available in the future. The software is developed in C#.

RIO Infrastructure

When the RIO project started, instead of adopting the early platforms for IoT, that changed enormously in the last few years (and required massive code rewrintings in some cases), the preferred solution was the enlargement of the platform already used for remote sensors with additional functionality and improved approaches where possible.

Therefore, initially the telemetry was posted onto a web endpoint, the alerts were dispatched with a specific service, and so on.

As soon as a messaging system appeared as a mandatory requirement, also the other functionality converged there, although you can find some references here and there to the initial stage. They were left for a reason apart from affection, though: the software is built to adapt to whatever infrastructure, thus allowing a better integration in existing solutions.

Using the Software

The code is released Open Source, according to the EC regulations and according to the MIT License, in order to fulfill the requirements of the Microsoft libraries used.

The main component of the RIO software, located in RIO, is called RIO.Manager. It is the kernel process of the guest Operating System, which will take care of orchestrating all the activities.

The Manager is a singleton, it requires to be configured using a Settings object, before being launched. Early single-step approaches limited a lot the capability of this object.

This is a first example of the need of a launcher, i.e., a program taking care of interfacing the RIO with the hosting Operating System: this program will take care of creating the communication channels, loading or creating the Settings object, and will also subscribe to the Manager events. These are used, for instance, to emit unsolicited messages from the RIO to the world.

Ideally, all the interactions of the RIO with the hosting OS should pass by the launcher; there are exceptions, though, that will be described.

Main Classes

  • Manager: the main component, it runs the RIO OS, creating and managing all the running components, handling the requests and publishing the contents generated internally
  • Settings: the configuration of the RIO is implemented by this class. It contains the configuration of the RIO itself and a set of Features, describing the components the RIO will configure and start
  • Scheduler: this component allows executing commands according to a specific schedule, implemented through a Ruleset
  • Ruleset: a collection of Rules, that when verified will require the execution of a set of commands
  • Feature: the configuration of a component to be ran in the RIO
  • Command: implemented by the subclasses of Action, are executables that the components can execute to perform specific actions
  • IChannel: a communication channel can be used to send, receive, or both; since the RIO is agnostic about the way information are exchanged, these are commodities for the launchers, more than components of RIO itself. The RIO.Communications library contains a set of implementations.

When the Manager starts, it loads all the plugins it can find to be able to implement the components defined in the Settings. This is one direct interaction with the hosting OS, that is not handled by the launcher.

Using the Extensibility Framework (Visual Studio flavour), the Manager looks for IFeature implementing classes: if a Feature described in the Setting has the type property equals to the name property of the IFeature, this is used to configure one or more Task to perform the required activities.

The way to create your own RIO is therefore to create a library defining an IFeature implementing class and decorating it with:

C#
[System.ComponentModel.CompositionExport(typeof(IFeature))]
public class Simulation : IFeature
{
    public string Name => typeof(Simulation).Name;
    public IEnumerable Configuration
    {
         get {
             return new Property[] { ... }
         }
    }
    public IEnumerable Commands { get { yield break; } }
    public IEnumerable Setup(Settings configuration, Feature settings) …
} 

The decoration is used when loading the library to find all classes to be used.

The Configuration is a list of configuration parameters the feature needs to configure its tasks, like the name of a serial port or its speed, a port number or a complete URL.

The Commands similarly provides a list of commands the task will execute. The commands’ implementations require the list of parameters they need to perform the requested action. The following list is an example of an SMS sending command, which requires a recipient and a message text, and allows using all additional provided parameters for macro substitions.

C#
public override IEnumerable<Parameter> Parameters => new Parameter[] {
    new Parameter { Type = "string", Name = "recipient", Required = true },
    new Parameter { Type = "string", Name = "message", Required = true },
    new Parameter { Type = "*", Name = "macro", Required = false } };

In order to send special data types used by the feature, it must supply their converters to serialize and deserialize their contents. For simple and standard data types, it is not necessary.

The default implementation of the Name property is the best solution.

The Setup method should always return an ITask, even if it was not possible to configure it: it is the only way for the ITask to report the error. Suppose now a Feature describe a humidity sensor and the RIO device is equipped with three of them positioned in different points of a greenhouse. The Settings will contain three different descriptions of the same feature with different parameters. In order to tell apart which sensor the data are coming from, a different name is supplied to each configuration. There cannot be then two different configurations with the same name, even if related to different features. In case Settings loaded by the implementation contains such a duplicate, only the first will be kept and the others deleted. All messages shared with the RIO infrastructure will then specify where the information comes from. If measurements are sent to the infrastructure, all measures from the same sensor will be grouped together.

The IFeature configuration will create one or more objects implementing ITask, that will execute your business logic. The ITask implementing classes may also provide the set of Commands they are able to execute.

Points of Interest

Security

The SSL+password approach to secure a REDIS connection proved to be enough for the time being; but the password is the same for all devices, that sometimes are deployed in the open with no access restriction. Tampering with one means having access to the whole infrastructure.

But this is just a possible implementation: using Azure IoT Hub, the system can benefit of safer communication protocols, that are better suited for small devices.

Flexibility

The RIO is more a description of the required components, plus a solid reference implementation. It can be adapted to a large variety of architecture and goes along well with legacy architectures.

History

The system is now pretty stable, but open to improvements, based on the feedback we'll receive.

License

This article, along with any associated source code and files, is licensed under The MIT License