Integrate IoT with a (c)VO (?) ============================== IoT Deployment ---------------------------- The VO is a runtime that has two interfaces. A NorthBound and a SouthBound interface. The SouthBound interface can be used to connect the VO to an IoT device. In the context of the NEPHELE project, we consider two different deployment models depending on whether the IoT device has decent computing capabilities or not: Deployment Type A ++++++++++++++++++++ .. figure:: ../images/deployment_a.png :align: center **Deployment Type A** In this deployment type, we assume that the IoT device is capable of deploying the VO-WoT runtime. This can be achieved either by installing the `Python package `_ or deploying the `Docker image `_ (the architectures currently supported are linux/amd64 and linux/arm64). Afterward, the developer needs to select which protocols will be activated on the IoT device's NorthBound interface. Then, the VO can connect to the VO runtime of the device and consume its data. Deployment Type B ++++++++++++++++++++ .. figure:: ../images/deployment_b.png :align: center **Deployment Type B** In this deployment type, we assume that the IoT device has limited computing capabilities and is not able to deploy the VO-WoT runtime. Therefore, the way to communicate with the VO is through the `VO's APIs `_. This means that the IoT device will need to use a client (e.g. HTTP or MQTT) to send data to the VO directly or to a broker that the VO is also listening to. In this setup, the IoT device initiates the communication. This option is more versatile since nothing needs to be deployed on the device but on the other hand, requires the proper formatting of the data being sent. Minimal VO-WoT deployment ---------------------------- Deployment Type A ++++++++++++++++++ For a more detailed guide on how to deploy the VO-WoT runtime refer to the `Quick Start Guide `_ and the `tutorial example `_. Essentially, the runtime is based on three-file format: (i) a JSON Thing Description based on the `Thing Description specification `_, (ii) a YAML VO Descriptor configuration file and (iii) a Python script file. The Thing Description contains Properties, Actions and Events. Each of these interactions are self-descriptive with the Properties containing all the information of the device (e.g., battery level, temperature sensor value, etc.), the Actions being responsible for all the functionality that needs to be executed (e.g. switch on/off light switch, send command to a device etc.) and the Events are occurences that can be monitored and subscribed to (e.g. subscription to a low battery event). The VO Descriptor contains all the necessary information to instantiate and configure the VO such as what protocols or what databases will be used along with consumed information from other VOs. Lastly, the Python script file is bound to Properties, Actions and Events and contains all the logic that will be executed for each of these interactions (e.g., property read/write, action invocation, event emission). After populating these files the user needs to simply execute the cli of the package: .. figure:: ../images/iot-vo-step1.png :align: center **Install VO-WOT CLI install** A minimal Thing Description (td.json) is: .. figure:: ../images/td-example.png :align: center **Thing Description JSON** This Thing Description defines a device named "Smart-Coffee-Machine" with the context of the Thing Description v.1.1 specification that specifies an unsecured scheme for communication. Next, Properties can be added: .. figure:: ../images/td-example-2.png :align: center **Minimal Thing Description JSON properties** These properties defined a nested property called "allAvailableResources" that encapsulates info about the water, milk, chocolate and coffee beans levels, while the "servedCounter" and "maintenanceNeeded" respectively are simple integer and boolean values. Actions can be set as: .. figure:: ../images/td-example-3.png :align: center **Minimal Thing Description JSON actions** This block defines a "makeDrink" action and specifies the input and output of the action. Lastly, events can be defined as: .. figure:: ../images/td-example-4.png :align: center **Minimal Thing Description JSON events** This block defines the "outOfResource" that triggers once some resource has been depleted. The Python script file can be used to set the behavior of the runtime once a property is read or an action is triggered. `A full example can be located here `_. In short functions named after the Properties, Actions and Events with proper suffixes can be created to manage this behavior. An object named "exposed_thing" is imported during instantiation and allows the user to interact with the VO's internal status. More specific example **Properties** - _init: property initial value. If not set, property reads will return None. - _read_handler: specifies the return value once the property is read. For example, this can be set to fetch current metrics from a device's sensors. - _write_handler: specifies what happens when a property is written to. For example, this can be used to modify the device's state. If the user doesn't define these two handlers, then the default ones will be used. These save internally all properties' values during property write operations and retrieve this saved information during property read operations. The default one can be used in conjunction with custom code as such: .. figure:: ../images/td-example-5.png :align: center **VO property handler** This will retrieve the internal saved value utilizing the "exposed_thing" object while printing a message or executing arbitrary code that the user needs. **Actions** - _handler: action invocation handler. Specifies what will happen when an action is invoked. If the handler is not defined, by default nothing will happen. For example: .. figure:: ../images/td-example-6.png :align: center **VO custom action handler** This will set bind the above code to the "setSchedule" action, read the input from the "input" key inside the params variable and alter the device's state while returning a result value. **Events** - _on_next: defines what code will run once a new event has been emitted. - _on_completed: defines what code will run once the subscription completes. - _on_error: defines what code will run in the event of an error in the subscription. In general the "_on_next" is the most important of the three. In the example below the user can define what happens when the "outOfResource" event is emitted. .. figure:: ../images/td-example-7.png :align: center **VO custom event handler** Lastly, the VO Descriptor will enable the necessary protocols for communication with other entities. All the available options are `available here `_ and a also `complete example of the coffee machine `_. The linked example activates the HTTP and CoAP protocols in ports 8080 and 5683 respectively and enables the catalogue HTTP server at port 9090 of the runtime. The catalogue server is an HTTP server that serves the Thing Description JSON file. This is crucial since this file needs to be consumed by all interested clients (either other VOs or applications). Deployment Type B ++++++++++++++++++ In the deployment Type B, the device doesn't deploy the VO-WoT runtime. In that case, the VO needs to be deployed normally with the three-file format (Thing Description JSON, VO Descriptor YAML, Python script file) and the device can communicate with the VO using the VO's NorthBound interface. In the above sections, all the underlying protocols are abstracted and handled by the API. However, in Deployment Type B this will need to be handled manually by the developer. For example, if the VO is configured to start an HTTP server in port 8080 and specifies a property named "temperature" then the device can directly communicate with the VO and interact with the property. This is achieved through `HTTP calls `_ for the HTTP protocol. A property read for example translates to an HTTP GET command to the URL "http://localhost:8080/vo/property/temperature". A similar approach is used for `all other protocols `_. VO deployment ++++++++++++++ Manual VO deployment @@@@@@@@@@@@@@@@@@@@@@@@ If all the previous steps have been accomplished similarly to the `minimal example `_, then a device has deployed the runtime and is exposing its catalogue at a URL similar to "http://127.0.0.1:9090/smart-coffee-machine" (replace the host and device name accordingly). Hitting this endpoint should return the Thing Description JSON. That means that the device is ready for the connection with a VO. In general, to deploy a VO the steps are the same as above. The main difference lies in the SouthBound interface. This interface is used to connect to the device. The relevant fields in the VO Descriptor (marked as "bindingSB") are used to set communication credentials for authentication to a device/VO. Additionally, the "consumedVOs" and "proxy" keys of the VO Descriptor can be used to connect to VOs. .. figure:: ../images/td-example-8.png :align: center **VO descriptor** **consumedVOs** This section defines the VOs that will be consumed. If this VO consumes a device's data then by setting a key with the device's Thing name (e.g. "smart-coffee-machine") and the URL of the catalogue port (e.g. http://127.0.0.1:9090/smart-coffee-machine). Once this key is declared a special variable called "consumed_vos" is injected into the Python script file and can be used as a handle to invoke all the APIs operations (property read/write, function invocation). `More information `_. The "events" and "propertyChanges" keys can be used to automatically subscribe to the device's events or property changes and be bound to the corresponding "_on_next" function of the Python script file for example. The process to create a cVO that consumes information from one or multiple VOs in identical to the process needed to connect a VO to a device. **proxy** The proxy can be used to directly mirror properties, actions and events. That means that a local property operation (e.g. read or write) of the VO can be delegated to a remote VO/device. The best way to utilize this functionality is to create an identical Thing Description to the device's containing all the Properties, Actions and Events. By utilizing the "proxy" key of the Descriptor, all interactions will be delegated to the device effectively making the VO a virtual representation of the device. Of course, which ones will be exposed or delegated to the device is up to the developer. This is just a convenience to automatically delegate interactions to a device. VO deployment Helmchart @@@@@@@@@@@@@@@@@@@@@@@@@@ In the case of Kubernetes deployments, a Helmchart can be created for the VO to minimize deployment time using the `template `_. The user simply needs to fill the files in the "scripts" directory and then deploy the helmchart.