From 0e9074947098569d487abcc487b449f9b4ffdea6 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" Every time a WireAsset receives an envelope on its input port, it will read the values of all of its channels with For each channel in asset configuration with READ or READ_WRITE type named name: For example, if the Asset attached to the Modbus Driver shown in the picture below receives a WireEnvelope on its input port, it can emit an envelope with the following content, assuming that the read operation for each channel succeed: For example, if an Asset that has the channel configuration shown in the picture below receives a WireEnvelope on its input port, it can emit an envelope with the following content, assuming that the read operation for each channel succeed: The WireAsset component provides the following global (non per-channel) configuration parameters that can be used to customize component behavior: emit.all.channels: Specifies whether the values of all READ or READ_WRITE channels should be emitted when a channel event is received in listen mode. If set to true, the values for all channels will be read and emitted, if set to false, only the value for the channel related to the event will be emitted. timestamp.mode: Allows to configure how timestamps are emitted, the following modes are supported: NO_TIMESTAMPS: no timestamp-related properties will be emitted. PER_CHANNEL: the component will emit a driver-generated timestamp property per channel, as the value of the SINGLE_ASSET_GENERATED: the component will emit a single timestamp per request, generated by the Asset itself before emitting the envelope as the value of the SINGLE_DRIVER_GENERATED_MAX and SINGLE_DRIVER_GENERATED_MIN: the component will emit a single driver generated timestamp being respectively the max (most recent) or min (oldest) among the timestamps of the channels as the value of the emit.errors: Specifies whether channel specific errors should be included or not in emitted envelopes. If enabled, the component will add an additional property per channel, named emit.connection.errors: Specifies whether the component should emit an envelope in case of a general connection exception reported by the Driver (for example due to the fact that the connection with a remote device cannot be established). The error message associated with the exception will be emitted in a property named WireEnvelope emit.on.change: If set to true, this component will include a channel value in the output emitted in Kura Wires only if it differs from the last emitted value for that channel. Channel errors will always be emitted if emit.errors is set to emit.empty.envelopes: If set to false, this component will not emit empty envelopes. The emergence of an Internet of Thing (IoT) service gateway model running modern software stacks, operating on the edge of an IoT deployment as an aggregator and controller, has opened up the possibility of enabling enterprise level technologies to IoT gateways. Advanced software frameworks, which abstract and isolate the developer from the complexity of the hardware and the networking sub-systems, re-define the development and re-usability of integrated hardware and software solutions. Eclipse Kura is an Eclipse IoT project that provides a platform for building IoT gateways. It is a smart application container that enables remote management of such gateways and provides a wide range of APIs for allowing you to write and deploy your own IoT application. Kura runs on top of the Java Virtual Machine (JVM) and leverages OSGi, a dynamic component system for Java, to simplify the process of writing reusable software building blocks. Kura APIs offer easy access to the underlying hardware including serial ports, GPS, watchdog, USB, GPIOs, I2C, etc. It also offer OSGI bundle to simplify the management of network configurations, the communication with IoT servers, and the remote management of the gateway. Kura components are designed as configurable OSGi Declarative Service exposing service API and raising events. While several Kura components are in pure Java, others are invoked through JNI and have a dependency on the Linux operating system. Kura comes with the following services: After developing your application and generating a deployment package that contains the bundles to be deployed (refer to the Development section for more information), you may install it on the gateway using the Packages option in the System area of the Kura Gateway Administration Console as shown below. Upon a successful installation, the new component appears in the Services list (shown as the Heater example in these screen captures). Its configuration may be modified according to the defined parameters as shown the Heater display that follows. Kura allows the installation and update of running applications via the Eclipse Kura Marketplace. The Packages page has, in the top part of the page a section dedicated to the Eclipse Kura Marketplace. Dragging an application reference taken from the Eclipse Kura Marketplace to the specific area of the Kura Web Administrative Console will instruct Kura to download and install the corresponding package, as seen below: Warning If the installation from the Eclipse Marketplace fails, it can be for the lack of the correct certificates. In this case, import the certificate in the SSLKeystore from the Certificate List tab under the Security section. For more details about the procedure see here. If the bundle is an official add-on for Eclipse Kura, the following certificate has to be imported: that has the following description: If the bundle is not an official one and it is not hosted by Eclipse, retrieve the certificate with this command: Assets as Wire Components
Read mode
READ
or READ_WRITE
type. The result is emitted as a WireEnvelope with a single WireRecord. The WireRecord contains the following properties:
-
+assetName
, value type STRING and the emitting asset asset name as value
-For each channel in asset configuration with READ or READ_WRITE type named name:assetName
, value type STRING and the emitting asset asset name as valueassetError
, value type STRING if emit.errors and emit.connection.errors is enabled and a general connection failure is returned by the Driver. See the description of the emit.connection.errors parameter for more details.assetTimestamp
, value type LONG, reporting a timestamp in milliseconds since Unix epoch (midnight, January 1, 1970 UTC). This property may be present or not depending on the value of the timestamp.mode configuration parameter or in case of general connection exception reported by the Driver, see the configuration parameter description for more details.
-<name>_timestamp
value type = LONG
reporting a timestamp in milliseconds since UNIX epoch. This property will be present only if the timestamp.mode Asset configuration property is set to PER_CHANNEL
<name>_error
, value type = STRING
reporting an error message. This property will be present only if read operation fails and the emit.errors Asset configuration property is set to true.
@@ -4555,6 +4577,53 @@
+Write mode
bar
property will have no effect, since none of the defined channels has foo
as name.READ
or READ_WRITE
, since a WireEnvelope has been received.Wire Asset global configuration parameters
+
+
diff --git a/docs-release-5.6/search/search_index.json b/docs-release-5.6/search/search_index.json
index b0b6d52e97..55110557c7 100644
--- a/docs-release-5.6/search/search_index.json
+++ b/docs-release-5.6/search/search_index.json
@@ -1 +1 @@
-{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Home","text":""},{"location":"#welcome-to-the-eclipse-kuratm-documentation","title":"Welcome to the Eclipse Kura\u2122 Documentation","text":"
+
+<channel name>_timestamp
property.assetTimestamp
property.assetTimestamp
property.<channel_name>_error
. If the channel operation fails, the property value will be an error message reported by the Driver, if the operation succeeds the property value will be the empty string.assetError
. In case of connection exception, channel values are not available and no channel related properties will be emitted. If the timestamp.mode property is set to a value other than NO_TIMESTAMPS, the component will also emit a assetTimestamp
property reporting current system time. This property will be ignored if emit.errors is disabled. Example of emitted envelope contents:
+
+
+
+myAsset
(type = STRING
)Connection refused
(type = STRING
)1597925200
(type = LONG
)true
. If as a result of a read operation no changes are detected in any referenced channel, the Asset will emit an envelope containing no channel values, unless emit.empty.envelopes is set to false
.
"},{"location":"administration/application-management/","title":"Application Management","text":""},{"location":"administration/application-management/#package-installation","title":"Package Installation","text":"
-----BEGIN CERTIFICATE-----\nMIIHxzCCBq+gAwIBAgIQCCxCSNb4iszmNPNCflUcGTANBgkqhkiG9w0BAQsFADBP\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMSkwJwYDVQQDEyBE\naWdpQ2VydCBUTFMgUlNBIFNIQTI1NiAyMDIwIENBMTAeFw0yMzA5MTEwMDAwMDBa\nFw0yNDEwMTEyMzU5NTlaMG8xCzAJBgNVBAYTAkNBMRAwDgYDVQQIEwdPbnRhcmlv\nMQ8wDQYDVQQHEwZPdHRhd2ExJTAjBgNVBAoTHEVjbGlwc2Uub3JnIEZvdW5kYXRp\nb24sIEluYy4xFjAUBgNVBAMMDSouZWNsaXBzZS5vcmcwggIiMA0GCSqGSIb3DQEB\nAQUAA4ICDwAwggIKAoICAQC5hXH2cQoOQlXs5cQ5itZ1Dzct9R+bqr2HaF+imlgo\nxJ+Vw1ukfQPpSbmSO17A0hLgpSJyVgoPlpOKkg6LGTz8/2qB7DWHdQbg2p0IGQhr\ndm4oJN2qknnGNl/YYkjz2QJswr1M98raydmq0hqJi0M3q9JSO64O3wOMNduvNG+O\nrCBol7cbxLr7NNoFxZncZ9giP7QF0XYS6nA8dtIyXU3SARRSPn6y9OX1ttltveck\n41ocaU8ORiTF7i89t649XAbtsvxUWM+qVnvlMxpaXqbhnrXMQ/pV2yfdU/qiFQth\n+RqFgBYoX5roxvmjB14+2qlymn236N4KOGhvfr+Fp8C8Fv6N6wFyKZctXewQ6IsA\n3zDvJmF3QaCz6h88lg+IqbRjX5MOjhSkE7XDNKb+xAw5pYzkn9LP+QJLf0iYJw2D\nZ/X+InVPiZ5UdXyXWypN3q0W5vlz/TmWuVZv76/azZ3anoSPiKh+F3si1xZVEMZQ\nIkqsgUfq69M4KvHrdi4nGEOfdBHxjos9ul1AsJR57hrhIchsESthUK04e7d2LYOB\nhHAr0uJNdwFsFD2EBR25ogN83bZ8NaDrrdK2P6sV+hWWK+MY1qRuRub7/fYuR4AU\n82toms9p1usjuyMmuIGEpLwk7jZe6XITcbXQEXDA8JKSZrZ/mOA4yTfIGR/gXXB7\nwQIDAQABo4IDfTCCA3kwHwYDVR0jBBgwFoAUt2ui6qiqhIx56rTaD5iyxZV2ufQw\nHQYDVR0OBBYEFO8gL5LNWmSgCqbujR1qH0bUfrIrMCUGA1UdEQQeMByCDSouZWNs\naXBzZS5vcmeCC2VjbGlwc2Uub3JnMD4GA1UdIAQ3MDUwMwYGZ4EMAQICMCkwJwYI\nKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNVHQ8BAf8E\nBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMIGPBgNVHR8EgYcw\ngYQwQKA+oDyGOmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRMU1JT\nQVNIQTI1NjIwMjBDQTEtNC5jcmwwQKA+oDyGOmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0\nLmNvbS9EaWdpQ2VydFRMU1JTQVNIQTI1NjIwMjBDQTEtNC5jcmwwfwYIKwYBBQUH\nAQEEczBxMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wSQYI\nKwYBBQUHMAKGPWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRM\nU1JTQVNIQTI1NjIwMjBDQTEtMS5jcnQwDAYDVR0TAQH/BAIwADCCAX4GCisGAQQB\n1nkCBAIEggFuBIIBagFoAHYAdv+IPwq2+5VRwmHM9Ye6NLSkzbsp3GhCCp/mZ0xa\nOnQAAAGKhcgXYgAABAMARzBFAiEApQsk19PxbsLa452EPaPCXe7SAtpbm5RHnrwj\nyKAjWx0CICli5A3XAGwmg7IEy4lVA5YBt+mhvlegWkXrKt+oc/CoAHUASLDja9qm\nRzQP5WoC+p0w6xxSActW3SyB2bu/qznYhHMAAAGKhcgXWQAABAMARjBEAiAvx7lc\nMyKS6bbnsjbzYOLzJbcS2aAjCzQz4mFiuFA59AIgbt+rpE40/RO0JnFyLP9fsbUf\npUj16ZYinOLorqDk9r0AdwDatr9rP7W2Ip+bwrtca+hwkXFsu1GEhTS9pD0wSNf7\nqwAAAYqFyBc3AAAEAwBIMEYCIQDCrdQYGYA7BlsT5gXZmkutN15gDQDjlfJBxIRb\nZ0FAAgIhAIr0eNFvkpec6VJ5pPrNklFt78XP0NjEOJxjrCFTLKVdMA0GCSqGSIb3\nDQEBCwUAA4IBAQCvENXlAGP311/gV5rMD2frsK+hlcs/4wjRKUS+nwp3RLTRd3w4\ncZLHcsw9qCxeniuHsc/Wa6myr0kKdRc4V6movLq9vMdSjT9dDOZWtZgFaadB0+z2\nA/Jsq1/AFFWqWisF64627j/Wf7RwuasxM0dnkAl3m9Hli5xKPgjbovXiH/dCeMvS\nMTxD1p3ewIYITzV+1Q5FoFuGyIyuh1Kzo7A41xKPe+XfWHqt+hKL8MWkJ9ACD2b0\nZDlD2OaX7K+vI8aWprmwVdpp3deuUoHgBqa1PkHPRmP0bFbamBdB4H6goRX5+DEy\ncTW2rRm8jFiLm1kf0/iOL7/ddw0yZQAUMthU\n-----END CERTIFICATE-----\n
Common Name: *.eclipse.org\nSubject Alternative Names: *.eclipse.org, eclipse.org\nOrganization: Eclipse.org Foundation, Inc.\nLocality: Ottawa\nState: Ontario\nCountry: CA\nValid From: September 10, 2023\nValid To: October 11, 2024\nIssuer: DigiCert TLS RSA SHA256 2020 CA1, DigiCert Inc Write review of DigiCert\nKey Size: 4096 bit\nSerial Number: 082c4248d6f88acce634f3427e551c19\n
openssl s_client -showcerts -connect <download_link>:443\n
and import it in the SSLKeystore.
"},{"location":"administration/application-management/#package-signature","title":"Package Signature","text":"Once the selected application deployment package (dp) file is installed, it will be listed in the Packages page and detailed with the name of the deployment package, the version and the signature status. The value of the signature field can be true if all the bundles contained in the deployment package are digitally signed, or false if at least one of the bundles is not signed.
"},{"location":"administration/directory-layout/","title":"Directory Layout","text":"
This section describes the default Kura directory layout that is created upon installation. The default installation directory is as follows:
/opt/eclipse\n
The kura sub-directory is a logical link on the actual Kura release directory:
kura -> /opt/eclipse/kura_3.0.0_raspberry-pi-2\nkura_3.0.0_raspberry-pi-2\n
"},{"location":"administration/directory-layout/#kura-file-structure","title":"Kura File Structure","text":"The idea behind the Kura file and folder structure is to separate user and framework configuration files, that is files that can be modified by the user to customize Kura behavior and files that are used by Kura to persist configurations. Moreover, some files are generated at runtime by Kura (i.e. database) and they are kept in specific folders.
The user
, console
, log4j
and packages
directories contain files that can be modified by the user (i.e. the configuration for the logging or custom Kura properties). The framework
folder keeps the configuration files used by Kura and that shouldn't be modified by the user. The data
directory is used to persist files that are generated by Kura. Finally, the plugins
folder contains all the jar files needed by Kura. All of the Kura files are located within /opt/eclipse/kura
folder using the structure shown in the following table:
bin
Scripts that start Kura. console
This folder contains files that are used to customise the Kura Web UI appearance. data
Data files generated by the Kura runtime. data/persistance
Embedded Database files. packages
Deployment package files that are not part of the standard Kura framework, but are installed at a later time. framework
Configuration data for Kura framework. The user shouldn't directly modify these files. log
Log file from the latest Kura installation. log4j
Logger framework configuration plugins
All of the libraries and Kura specific jar files needed for the framework execution. user
Configuration files generated by the user or by Kura at runtime. These files can be modified by the user to customise the Kura behavior. user/snapshots
XML snapshot files; up to 10 successive configurations including the original. user/security
Files used by Kura to configure security. .data
Backup files needed to restore factory configuration"},{"location":"administration/directory-layout/#log-files","title":"Log Files","text":"Kura regularly updates two log files in the /var/log directory:
/var/log/kura-console.log - stores the standard console output of the application. This log file contains the eventual errors that are thrown upon Kura startup.
/var/log/kura.log - stores all of the logging information from Kura bundles. The logger levels are defined in the log4j.xml configuration file as shown below:
/opt/eclpse/kura/user/log4j.xml\n
The default logger level in this file is set to INFO. This level may be modified for the whole application or for a specific package as shown in the following example:
<Loggers>\n <Logger name=\"org.eclipse\" level=\"info\" additivity=\"false\">\n <AppenderRef ref=\"RollingFile\"/>\n </Logger>\n\n <Logger name=\"org.eclipse.kura.net.admin\" level=\"debug\" additivity=\"false\">\n <AppenderRef ref=\"RollingFile\"/>\n </Logger>\n\n <Root level=\"info\">\n <AppenderRef ref=\"RollingFile\"/>\n </Root>\n</Loggers>\n
In this example, the logger level is set to DEBUG only for the net.admin bundle. Additionally, more specific, properties may be defined as required for your particular logging needs. The logger levels are hierarchical, so that those in a deeper level of the hierarchy will apply; otherwise, the more general logger level will override them.
Once the logger levels are modified as needed and the log4j.xml configuration file is saved, Kura automatically loads the new configuration. By default Kura checks the file every 30 seconds.
"},{"location":"administration/remote-management-kapua/","title":"Remote Management with Eclipse Kapua","text":""},{"location":"administration/remote-management-kapua/#built-in-services-management","title":"Built-in Services Management","text":"This section describes the remote management of devices running Kura via Eclipse Kapua Console. The Eclipse Kapua Web Console provides the administration tools used for the management of the built-in services exposed by Kura.
To remotely manage a device running Kura through the Eclipse Kapua Web Console, select the desired device from the Devices Table of the console and open the Configuration tab as shown in the screen capture below. Please refer to the Built-in Services section for a description of the available Services and their configuration parameters.
"},{"location":"administration/remote-management-kapua/#installation-of-a-new-application","title":"Installation of a New Application","text":"As described in Application Management, a new application embedded in a deployment package can be deployed and configured using Eclipse Kapua Console.
To do so, select a connected device and click on the Packages tab. Then, click on Install/Upgrade. The Install New Package window opens allowing the deployment package to be installed from an URL as shown in the screen capture below. Once installed, the new application parameters may be modified in the same way as the Built-in Services. Click on the Configuration tab to see the service that corresponds to your application.
"},{"location":"administration/remote-management-kapua/#snapshots","title":"Snapshots","text":"As described in Snapshot Management, the overall Kura configuration, including the new installed applications, is stored in a snapshot xml file. The Eclipse Kapua Console also provides options to Download, Upload and Apply, or Rollback snapshots as shown in the screen capture below.
"},{"location":"administration/remote-management-kapua/#remote-command-execution-from-eclipse-kapua-web-console","title":"Remote Command Execution from Eclipse Kapua Web Console","text":"The Eclipse Kapua Console provides the ability to run system commands directly on the device. Refer to Command Service for details on how to configure this service in Kura.
It is also possible to send a script to execute using the File option of the Command tab in Eclipse Kapua Console as shown in the screen capture below. This script must be compressed into a zip file with the eventual associated resource files. Once the file is selected, click Execute.
The zip file is sent embedded in an MQTT message on the device. The Command Service in the device stores the file in /tmp, unzips it, and tries to execute a shell script if one is present. Note that in this case, the Execute parameter cannot be empty; a simple command, such as \"ls -l /tmp\", may be entered.
"},{"location":"administration/snapshot-management/","title":"Snapshot Management","text":"The overall configuration of Kura is stored in an XML file called a snapshot. This file includes all of the parameters for every service running in Kura. The original configuration file is named snapshot_0.xml. This section describes how snapshots may be used.
Each time a configuration change is made to one of the Kura components, a new XML file is created using the naming convention snapshot_[time as a long integer].xml. The nine most recent snapshots are saved, as well as the original snapshot 0.
"},{"location":"administration/snapshot-management/#how-to-access-snapshots","title":"How to Access Snapshots","text":"To display snapshots using the Gateway Administration Console, select Settings from the System area, and then click on the Snapshots tab. The following three operations are available: Download, Upload and Apply, and Rollback.
"},{"location":"administration/snapshot-management/#how-to-use-snapshots","title":"How to Use Snapshots","text":""},{"location":"administration/snapshot-management/#download","title":"Download","text":"The Download option provides the ability to save a snapshot file onto your computer. This file may then be edited, uploaded back to the device, or transferred to another equivalent device.
Starting from Kura 5.1, the snapshot can be downloaded in two formats:
takeSnapshot
parameter specified by the CONF-V2 request is missing from the downloaded JSON file, if that parameter is not specified, a new snapshot will be created by default.Pressing the Download button will trigger a dialog that allows choosing the desired format.
"},{"location":"administration/snapshot-management/#upload-and-apply","title":"Upload and Apply","text":"The Upload and Apply option provides the ability to import an XML file from your computer and upload it onto the device. This function updates every service in Kura with the parameters defined in the XML file.
Warning
Carefully select the file to be uploaded. An incorrect file may crash Kura and make it unresponsive.
"},{"location":"administration/snapshot-management/#rollback","title":"Rollback","text":"The Rollback option provides the ability to restore the system to a previous configuration.
"},{"location":"administration/system-component-inventory/","title":"System Component Inventory","text":"The Framework has the capability to report locally and to the associated cloud platform the list of currently installed components and their associated properties.
This feature allows, locally and remotely, the system administrator to know which components are installed into the target device and the associated versions. The feature is particularly important for a system administrator because allows to identify vulnerable components and allows immediate actions in response.
From the local Kura Web UI, the list of system components is available in the System Packages tab of the Device section. Once selected, the user will get the list of all the system installed components.
The component's inventory list is available also via REST APIs and, with the same contract, from the cloud. The Mqtt contract defined for this component is available here
"},{"location":"cloud-api/app-dev-guide/","title":"Application developer guide","text":"This guide will provide information on how an application developer can leverage the new Generic Cloud Services APIs, in order to be able to properly use the CloudPublisher/CloudSubscriber API, publish a message, being notified of message delivery and of connection status changes.
The Kura ExamplePublisher will be used as a reference.
The application should bind itself to a CloudPublisher
or CloudSubscriber
instance, this can be done in different ways, such as using OSGi ServiceTracker
s or by leveraging the Declarative Service layer.
The recommended way to perform this operation is choosing the latter and allowing the user to customize the service references through component configuration.
If the component metatype and definition are structured as described below, the Kura Web UI will show a dedicated widget in component configuration that helps the user to pick compatible CloudPublisher
or CloudSubscriber
instances.
Write component definition
The first step involves declaring the Publisher or Subscriber references in component definition:
<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\"\n name=\"org.eclipse.kura.example.publisher.ExamplePublisher\"\n activate=\"activate\"\n deactivate=\"deactivate\"\n modified=\"updated\"\n enabled=\"true\"\n immediate=\"true\"\n configuration-policy=\"require\">\n <implementation class=\"org.eclipse.kura.example.publisher.ExamplePublisher\"/>\n\n <!-- If the component is configurable through the Kura ConfigurationService, it must expose a Service. -->\n <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.example.publisher.ExamplePublisher\"/>\n <service>\n <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n </service>\n\n <reference name=\"CloudPublisher\"\n policy=\"static\"\n bind=\"setCloudPublisher\"\n unbind=\"unsetCloudPublisher\"\n cardinality=\"0..1\"\n interface=\"org.eclipse.kura.cloudconnection.publisher.CloudPublisher\"/>\n <reference name=\"CloudSubscriber\"\n policy=\"static\"\n bind=\"setCloudSubscriber\"\n unbind=\"unsetCloudSubscriber\"\n cardinality=\"0..1\"\n interface=\"org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber\"/>\n </scr:component>\n
The snipped above shows the definition of Kura ExamplePublisher, this component is capable of sending and receiving messages, and therefore defines two references, the first to a CloudPublisher
and the second to a CloudSubscriber
.
In order to allow the user to customize the bindings at runtime, the target
attribute of the references should not be specified at this point in component definition, as it will be set by the Web UI.
Reference cardinality should be use the 0..1
or 0..n
form, as it is not guaranteed that the references will point to a valid service instance during all the lifetime of the application component. For example, references can not be bound if the application has not been configured by the user yet or if the target service is missing.
Create component metatype
Application metatype should declare an AD
for each Publisher/Subscriber reference declared in component definition:
<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n <OCD id=\"org.eclipse.kura.example.publisher.ExamplePublisher\"\n name=\"ExamplePublisher\"\n description=\"Example of a Configuring Kura Application.\">\n\n <!-- ... -->\n\n <AD id=\"CloudPublisher.target\"\n name=\"CloudPublisher Target Filter\"\n type=\"String\"\n cardinality=\"0\"\n required=\"true\"\n default=\"(kura.service.pid=changeme)\"\n description=\"Specifies, as an OSGi target filter, the pid of the Cloud Publisher used to publish messages to the cloud platform.\">\n </AD>\n\n <AD id=\"CloudSubscriber.target\"\n name=\"CloudSubscriber Target Filter\"\n type=\"String\"\n cardinality=\"0\"\n required=\"true\"\n default=\"(kura.service.pid=changeme)\"\n description=\"Specifies, as an OSGi target filter, the pid of the Cloud Subscriber used to receive messages from the cloud platform.\">\n </AD>\n\n <!-- ... -->\n\n </OCD>\n <Designate pid=\"org.eclipse.kura.example.publisher.ExamplePublisher\" factoryPid=\"org.eclipse.kura.example.publisher.ExamplePublisher\">\n <Object ocdref=\"org.eclipse.kura.example.publisher.ExamplePublisher\"/>\n </Designate>\n </MetaData>\n
It is important to respect the following rules for some of the AD
attributes:
id
This attribute must have the following form:
<reference name>.target\n
where <reference name>
should match the value of the name
attribute of the corresponding reference in component definition.
required
must be set to true
default
must not be empty and must be a valid OSGi filter.
The Web UI will renderer a dedicated widget for picking CloudPublisher
and CloudSubscriber
instances:
Write the bind/unbind methods in applicaiton code
The last step involves defining some bind...()
/unbind...()
methods with a name that matches the values of the bind
/unbind
attributes of the references in component definition.
public void setCloudPublisher(CloudPublisher cloudPublisher) {\n...\n}\n\npublic void unsetCloudPublisher(CloudPublisher cloudPublisher) {\n...\n}\n\npublic void setCloudSubscriber(CloudSubscriber cloudSubscriber) {\n...\n}\n\npublic void unsetCloudSubscriber(CloudSubscriber cloudSubscriber) {\n...\n}\n
As stated above, since reference cardinality is declared as 0..
, the application must be prepared to handle the cases where references are not satisfied, and therefore CloudPublisher
and CloudSubscriber
instances are not available.
Publish a message
If a CloudPublisher
instance is bound, the application can publish messages using its publish()
method:
if (nonNull(this.cloudPublisher)) {\n KuraMessage message = new KuraMessage(payload);\n String messageId = this.cloudPublisher.publish(message);\n }\n
Receiving messages using a CloudSubscriber
In order to receive messages from a CloudSubscriber
, the application must implement and attach a CloudSubscriberListener
to it.
This can be done for example during CloudSubscriber
binding:
public class ExamplePublisher implements CloudSubscriberListener, ... {\n\n ...\n\n public void setCloudSubscriber(CloudSubscriber cloudSubscriber) {\n this.cloudSubscriber = cloudSubscriber;\n this.cloudSubscriber.registerCloudSubscriberListener(ExamplePublisher.this);\n ...\n }\n\n public void unsetCloudSubscriber(CloudSubscriber cloudSubscriber) {\n this.cloudSubscriber.unregisterCloudSubscriberListener(ExamplePublisher.this);\n ...\n this.cloudSubscriber = null;\n }\n\n ...\n\n @Override\n public void onMessageArrived(KuraMessage message) {\n logReceivedMessage(message);\n }\n\n ...\n\n }\n
The CloudSubscriber will invoke the onMessageArrived()
method when new messages are received.
Receiving connection state notifications
If an application is interested in cloud connection status change events (connected, disconnected, etc), it can implement and attach a CloudConnectionListener
to a CloudPublisher
or CloudSubscriber
instance.
public class ExamplePublisher implements CloudConnectionListener, ... {\n\n ...\n\n public void setCloudPublisher(CloudPublisher cloudPublisher) {\n this.cloudPublisher = cloudPublisher;\n this.cloudPublisher.registerCloudConnectionListener(ExamplePublisher.this);\n ...\n }\n\n public void unsetCloudPublisher(CloudPublisher cloudPublisher) {\n this.cloudPublisher.unregisterCloudConnectionListener(ExamplePublisher.this);\n ...\n this.cloudPublisher = null;\n }\n\n public void setCloudSubscriber(CloudSubscriber cloudSubscriber) {\n this.cloudSubscriber = cloudSubscriber;\n ...\n this.cloudSubscriber.registerCloudConnectionListener(ExamplePublisher.this);\n }\n\n public void unsetCloudSubscriber(CloudSubscriber cloudSubscriber) {\n ...\n this.cloudSubscriber.unregisterCloudConnectionListener(ExamplePublisher.this);\n this.cloudSubscriber = null;\n }\n\n ...\n\n @Override\n public void onConnectionEstablished() {\n logger.info(\"Connection established\");\n }\n\n @Override\n public void onConnectionLost() {\n logger.warn(\"Connection lost!\");\n }\n\n @Override\n public void onDisconnected() {\n logger.warn(\"On disconnected\");\n }\n\n ...\n\n }\n
Receiving message delivery notifications
If an application is interested in message confirmation events and the underlying cloud connection supports it, it can implement and attach a CloudDeliveryListener
to a CloudPublisher
instance.
public class ExamplePublisher implements CloudDeliveryListener, ... {\n\n ...\n\n public void setCloudPublisher(CloudPublisher cloudPublisher) {\n this.cloudPublisher = cloudPublisher;\n ...\n this.cloudPublisher.registerCloudDeliveryListener(ExamplePublisher.this);\n }\n\n public void unsetCloudPublisher(CloudPublisher cloudPublisher) {\n ...\n this.cloudPublisher.registerCloudDeliveryListener(ExamplePublisher.this);\n this.cloudPublisher = null;\n }\n\n ...\n\n @Override\n public void onMessageConfirmed(String messageId) {\n logger.info(\"Confirmed message with id: {}\", messageId);\n }\n\n ...\n\n }\n
The CloudSubscriber will invoke the onMessageConfirmed()
method when a published message is confirmed.
In order to determine which message has been confirmed, the provided messageId
can be compared with the id returned by the publish()
call that published the message.
Please note that if the underlying cloud connection is not able to provide message confirmation for the published message, the id returned by publish()
will be null
.
Eclipse Kura provides by default a set of services used to connect to a cloud platform. The following sections describe the services and how to configure them.
The CloudService
API is deprecated since Kura 4.0. The functionalities provided by CloudService
are now provided by the CloudEndpoint
and CloudConnectionManager
service interfaces. See the section describing the Kura 4.0 cloud connection model for more details.
The DataService
and MqttDataTrasport
APIs are not deprecated in Kura 4.0.
The CloudService provides an easy-to-use API layer for the M2M application to communicate with a remote server. It operates as a decorator for the DataService, providing add-on features over the management of the transport layer.
In addition to simple publish/subscribe, the CloudService API simplifies the implementation of more complex interaction flows like request/response or remote resource management. The CloudService abstracts the developers from the complexity of the transport protocol and payload format used in the communication.
The CloudService allows a single connection to a remote server to be shared across more than one application in the gateway providing the necessary topic partitioning. Its functions include:
Adds application topic prefixes to allow for a single remote server connection to be shared across applications.
Defines a payload data model and provides default encoding/decoding serializers.
Publishes life-cycle messages when the device and applications start and stop.
To use this service, select the CloudServices option located in the System area and select the CloudService tab as shown in the screen capture below.
The CloudService provides the following configuration parameters:
device.display-name
- defines the device display name given by the system. (Required field.)device.custom-name
- defines the custom device display name if the device.display-name parameter is set to \"Custom\".topic.control-prefix
- defines the topic prefix for system messages.encode.gzip
- defines if the message payloads are sent compressed.republish.mqtt.birth.cert.on.gps.lock
- when set to true, forces a republish of the MQTT Birth Certificate when a GPS correct position lock is received. The device is then registered with its real coordinates. (Required field.)republish.mqtt.birth.cert.on.modem.detect
- when set to true, forces a republish of the MQTT Birth Certificate when the service receives a modem detection event. (Required field.)enable.default.subscriptions
- when set to true, the gateway will not be remotely manageable.payload.encoding
- Specify the message payload encoding. The possible options are Kura Protobuf and Simple JSON.The default CloudService implementations publishes the following lifecycle messages:
The MqttDataTransport service provides the ability to connect to a remote broker, publish messages, subscribe to topics, receive messages on the subscribed topics, and disconnect from the remote message broker. To use this service, select the MqttDataTransport option located in the System area and select the CloudService tab as shown in the screen capture below.
The MqttDataTransport service provides the following configuration parameters:
broker-url
- defines the URL of the MQTT broker to connect to. (Required field.)topic.context.account-name
- defines the name of the account to which the device belongs.username
and password - define the username and password that have been assigned to the device by the account administrator (generally username is account-name_broker). (Required field.)client-id
- defines the identifier of the MQTT client representing the device when connecting to the MQTT broker. If left empty, it is automatically determined by the client software as the MAC address of the main network interface (in general numbers and uppercase letters without ':'). This identifier has to be unique within your account.keep-alive
- defines the \"keep alive\" interval measured in seconds. It specifies the maximum amount of time that should pass without communication between the client and the server. The client will ensure that at least one message travels across the network within each keep alive period. In the absence of a data-related message during this time period, the client will send a very small MQTT \"ping\" message that the server will acknowledge. The keep alive interval enables the client to detect when the server is no longer available without having to wait for the long TCP/IP timeout. (Required field.)timeout
- sets the timeout used for all interactions with the MQTT broker. (Required field.)clean-session
- controls the behavior of both the client and the server at the time of connect and disconnect. When this parameter is set to true, the state information is discarded at connect and disconnect; when set to false, the state information is maintained. (Required field.)lwt
parameters - define the MQTT \"Last Will and Testament\" (LWT) settings for the client. In the event that the client unexpectedly loses its connection to the server, the server publishes the LWT message (lwt.payload) to the LWT topic on behalf of the client. This allows other clients (subscribed to the LWT topic) to be made aware that the client has disconnected. LWT parameters that may be configured include:lwt.topic
lwt.payload
lwt.qos
lwt.retain
in-flight.persistence
- defines the storage type where in-flight messages are persisted across reconnections. They may be stored in memory, or in a file on the disk. (Required field.)protocol-version
- defines the MQTT Protocol version to be used. This value may be 3.1 or 3.1.1.ssl
parameters - defines the SSL configuration. SSL parameters that may be configured include:ssl.hostname.verification
ssl.default.cipherSuites
ssl.certificate.alias
This guide will provide information on how a cloud connection developer can leverage the new Generic Cloud Services APIs.
As reference, this guide will use the Eclipse IoT WG namespace implementation bundle available here
"},{"location":"cloud-api/cloud-conn-dev-guide/#implement-cloudendpoint-and-cloudconnectionmanager","title":"Implement CloudEndpoint and CloudConnectionManager","text":"In order to leverage the new APIs, and be managed by the Kura Web UI, the Cloud Connection implementation bundle must implement CloudEndpont and, if log-lived connections are supported, the CloudConnectionManager interface must be implemented as well.
The ending class should be something as follows:
public class CloudConnectionManagerImpl\n implements CloudConnectionManager, CloudEndpoint, ... {\n\n @Override\n public boolean isConnected() {\n ...\n }\n\n @Override\n public void connect() throws KuraConnectException {\n ...\n }\n\n @Override\n public void disconnect() {\n ...\n }\n\n @Override\n public Map<String, String> getInfo() {\n ...\n }\n\n @Override\n public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n ...\n }\n\n @Override\n public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n ...\n }\n}\n
A corresponding component definition should be provided in the OSGI-INF folder exposing the implementation of CloudEndpoint and CloudConnectionManager interfaces.
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" enabled=\"true\" immediate=\"true\" modified=\"updated\" name=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager\">\n <implementation class=\"org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud.CloudConnectionManagerImpl\"/>\n <service>\n <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n <provide interface=\"org.eclipse.kura.cloudconnection.CloudConnectionManager\"/>\n <provide interface=\"org.eclipse.kura.cloudconnection.CloudEndpoint\"/>\n <!-- ... -->\n </service>\n\n <!-- ... -->\n\n <property name=\"kura.ui.service.hide\" type=\"Boolean\" value=\"true\"/>\n <property name=\"kura.ui.factory.hide\" type=\"String\" value=\"true\"/>\n</scr:component>\n
In order to be fully compliant with the Web UI requirements, the CloudConnection component definition should provide two properties kura.ui.service.hide
and kura.ui.factory.hide
to hide the component from the left side part of the UI dedicated to display the services list.
The CloudConnectionFactory is responsible to manage the cloud connection instance lifecycle by creating the CloudEndpoint instance and all the required services needed to publish or receive messages from the cloud platform.
As a reference, please have a look at the CloudConnectionFactory defined for the Eclipse IoT WG namespace implementation.
In particular, the getFactoryPid()
method returns the PID of the CloudEndpoint factory. The createConfiguration()
method receives a PID that will be used for the instantiation of the CloudEndpoint and for all the related services required to communicate with the cloud platform. In the example above, the factory creates the CloudEnpoint, and a DataService and MqttDataTransport instances internally needed to communicate with a remote cloud platform. As can be seen here, the CloudEndpoint instance configuration is enriched with the reference to the CloudConnectionFactory that generated it. This step is required by the Web UI in order to properly relate the instances with the corresponding factories.
The deleteConfiguration()
method deletes from the framework the CloudEndpoint instance identified by the PID passed as argument and all the related services. In the Eclipse IOT WG example, it not only deletes the CloudEndpoint instance but also the corresponding DataService and MqttDataTransport instances.
The getStackComponentsPids()
method return a List of String that represent the kura.service.pid of the configurable components that are part of a Cloud Connection instance. This method is used by the Web UI to get the list of configurable components that need to be displayed to the end user.
The getManagedCloudConnectionPids()
method will return the list of kura.service.pid of all the CloudEndpoints managed by the factory.
The factory component definition should be defined as follows:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" name=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.DefaultCloudConnectionFactory\">\n <implementation class=\"org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud.factory.DefaultCloudConnectionFactory\"/>\n <reference bind=\"setConfigurationService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.configuration.ConfigurationService\" name=\"ConfigurationService\" policy=\"static\" unbind=\"unsetConfigurationService\"/>\n <service>\n <provide interface=\"org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory\"/>\n </service>\n <property name=\"osgi.command.scope\" type=\"String\" value=\"kura.cloud\"/>\n <property name=\"osgi.command.function\" type=\"String\">\n createConfiguration\n </property>\n <property name=\"kura.ui.csf.pid.default\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager\"/>\n <property name=\"kura.ui.csf.pid.regex\" type=\"String\" value=\"^org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager(\\-[a-zA-Z0-9]+)?$\"/>\n <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.DefaultCloudConnectionFactory\"/>\n</scr:component>\n
In particular, it should expose in the service
section the fact that the factory implements org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory
<service>\n <provide interface=\"org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory\"/>\n </service>\n
Important properties that need to be specified to have a better Web UI experience are the following:
<property name=\"kura.ui.csf.pid.default\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager\"/>\n<property name=\"kura.ui.csf.pid.regex\" type=\"String\" value=\"^org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager(\\-[a-zA-Z0-9]+)?$\"/>\n
those allow to specify the form of the expected PID that the end user should provide when creating a new cloud connection."},{"location":"cloud-api/cloud-conn-dev-guide/#provide-a-cloudpublisher-implementation","title":"Provide a CloudPublisher implementation","text":"To provide a CloudPublisher implementation, other than implementing CloudPublisher API in a java class, the developer must provide a component definition in the OSGI-INF folder that should be like the following:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" enabled=\"true\" immediate=\"true\" modified=\"updated\" name=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher\">\n <implementation class=\"org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud.publisher.CloudPublisherImpl\"/>\n <service>\n <provide interface=\"org.eclipse.kura.cloudconnection.publisher.CloudPublisher\"/>\n <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n </service>\n <property name=\"cloud.connection.factory.pid\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager\"/>\n <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher\"/>\n <property name=\"kura.ui.service.hide\" type=\"Boolean\" value=\"true\"/>\n <property name=\"kura.ui.factory.hide\" type=\"String\" value=\"true\"/>\n <property name=\"kura.ui.csf.pid.default\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher\"/>\n <property name=\"kura.ui.csf.pid.regex\" type=\"String\" value=\"^org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher(\\-[a-zA-Z0-9]+)?$\"/>\n</scr:component>\n
As can be seen in the previous snippet, the Publisher exposes itself in the framework as a ConfigurableComponent
and as a CloudPublisher
.
The component definition must contain the following well-known properties:
cloud.connection.factory.pid
: this property must be set to the kura.service.pid of the factory that created the cloud connection which the publisher belongs. It is used by the Web UI to enforce that the correct cloud publisher implementation is used in a specific cloud endpoint. kura.ui.service.hide
: as specified before for the Cloud Endpointkura.ui.factory.hide
: as specified before for the Cloud Endpointkura.ui.csf.pid.default
: as specified before for the Cloud Factory. It is an optional property.kura.ui.csf.pid.regex
: as specified before for the Cloud Factory. It is an optional property.The relation between the CloudPublisher instance and the CloudEndpoint is defined by a configuration property set by the Web UI at CloudPublisher creation.
"},{"location":"cloud-api/cloud-conn-dev-guide/#provide-a-cloudsubscriber-implementation","title":"Provide a CloudSubscriber implementation","text":"The CloudSubscriber implementation and component definition is similar to the one described for the CloudPublisher.
"},{"location":"cloud-api/cloud-conn-dev-guide/#implement-requesthandler-support","title":"Implement RequestHandler support","text":"In order to support Command and Control, the cloud connection bundle should provide a service that registers itself as RequestHandlerRegistry. In this way all the RequestHandler instances could be able to discover the different Registry and subscribe for command and control messages received from the cloud platform. As an example, for the Eclipse IoT WG bundle, the CloudEndpoint registers itself also as RequestHandlerRegistry.
"},{"location":"cloud-api/overview/","title":"Overview","text":"This section describes the new cloud related concepts and APIs introduced in Kura 4.0.
"},{"location":"cloud-api/overview/#motivations","title":"Motivations","text":"Before Kura 4.0, Cloud APIs were quite tied to Kapua messaging conventions and to the MQTT protocol. Defining custom stacks that support other cloud platforms was possible, but the resulting implementations were affected by the following limitations:
The legacy APIs assume that the underlying messaging protocol is MQTT. This assumption spans across all API layers, from the low level MQTTDataTrasport
to the high level CloudClient
. This makes quite difficult to implement cloud stacks that use other protocols like AMQP or HTTP.
The CloudClient
API, which was the recommended way for applications to interface with a cloud stack, enforce the following MQTT topic structure:
#account-name/#device-id/#app-id/<app-topic>\n
This topic hierarchy, which is Kapua related, might be too restrictive or too loose for other cloud platforms, for example: accont-name
and device-id
parameters in the topic. Moreover, telemetry, alert and event message topics must start respectively the t/
, a/
and e/
prefixes. Adhering to this specification is not possible for a cloud stack that implements the legacy APIs.CloudClient
would be quite restrictive in this case. A way for overcoming this limitation for an application might be using the DataService layer directly, adversely affecting portability.CloudClient
in this case makes difficult for the cloud stack to enforce that the messages are published on the correct topics. Moreover, the cloud stack in this case must also convert from KuraPayload
to CSV, this can be currently achieved only by introducing rigid conversion rules, that might not be enough to support all message formats.Applications that use the current APIs are not portable across cloud platforms. For example if an appliaction intends to publish on Cumulocity or AWS, it should be probably aware of the underlying cloud platform.
The main interfaces of the new set of APIs and their interactions are depicted in the diagram below:
As shown in the above diagram new APIs introduce the concept of Cloud Connection, a set of related services that allow to manage the communication to/from a remote cloud platform.
The services that compose a Cloud Connection can implement the following cloud-specific interfaces:
CloudEndpoint (required): Each Cloud Connection is identified by a single instance of CloudEndpoint that implements low level specificities for the communication with the remote cloud platform.
CloudConnectionManager (optional): Exposes methods that allow to manage long-lived connections. The implementor of CloudEndpoint can implement this interface as well if the cloud platform support long-lived connections (for example by using the MQTT protocol).
RequestHandlerRegistry (optional): Manages the command and control functionalities if supported by the cloud platform.
CloudPublisher (optional): Allows applications to publish messages to the cloud platform in a portable way.
CloudSubscriber (optional): Allows applications to receive messages from the cloud platform in a portable way.
CloudConnectionFactory (required): Manages the lifecycle of Cloud Connections.
A Cloud Connection can also include services that do not provide any of the interfaces above but compose the internal implementation.
"},{"location":"cloud-api/overview/#cloudendpoint","title":"CloudEndpoint","text":"Every Cloud Connection must contain a single CloudEndpoint
instance. The kura.service.pid
of the CloudEndpoint
identifies the whole Cloud Connection.
The CloudEndpoint
provides some low level methods that can be used to interact with the remote cloud platform.
For example the interface provides the publish()
and subscribe()
methods that allow to publish or receive messages from the cloud platform in form of KuraMessage
s. Those methods are designed for internal use and are not intended to be used by end-user applications.
The format of the KuraMessage
provided to/received from a CloudEndpoint
is implementation specific: the CloudEndpoint
expects some properties to be set in the KuraMessage to be able to correctly publish a message (e.g. MQTT topic). These properties are specified by the particular CloudEndpoint
, and should be documented by the implementor.
The recommended way for applications to publish and receive messages involves using the Publisher and Subscriber APIs described below. If an application directly uses the methods above, it will lose portability and will be tied to the specific Cloud Connection implementation.
"},{"location":"cloud-api/overview/#cloudconnectionmanager","title":"CloudConnectionManager","text":"If the messaging protocol implemented by a Cloud Connection supports long-lived connection, then its CloudEndpoint
can also implement and provide the CloudConnectionManager
interface.
This interface exposes some methods that can be used to manage the connection like connect()
, disconnect()
and isConnected()
; it also supports monitoring connection state using the CloudConnectionListener
interface.
The limitations of the current model described above are addressed by the introduction of the CloudPublisher
and CloudSubscriber
APIs, that replace the CloudClient
as the recommended interface between applications and cloud stacks. CloudPublisher
and CloudSubscriber
are service interfaces defined as follows:
public interface CloudPublisher {\n\n public String publish(KuraMessage message) throws KuraException;\n\n public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener);\n\n public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener);\n\n public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener);\n\n public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener);\n\n}\n
public interface CloudSubscriber {\n\n public void registerCloudSubscriberListener(CloudSubscriberListener listener);\n\n public void unregisterCloudSubscriberListener(CloudSubscriberListener listener);\n\n public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener);\n\n public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener);\n\n}\n
"},{"location":"cloud-api/overview/#cloudpublisher","title":"CloudPublisher","text":"The CloudPublisher
interface should be used by applications for publishing messages using the single publish()
method. This method accepts a KuraMessage
which is basically a KuraPayload
that can be enriched with metadata.
The main difference with the CloudClient
APIs is that the publish()
method does not require the application to specify any information related to message destinations. This allows to write portable applications that are unaware of the low level details of the destination cloud platform, such as the message format and the transport protocol.
An application designed to receive messages from the cloud must now attach a listener (CloudSubscriberListener
) to a CloudSubscriber
instance.
In this case, the message source cannot be specified by the application but is defined by the subscriber instance, in the same way as the CloudPublisher
defines destination for published messages.
The low level details necessary for message delivery and reception (e.g. the MQTT topic and the conversion between KuraMessage
and the message format used on the wire) are managed by the publisher/subscriber, typically these details are stored in the service configuration.
While in the previous model an application was responsible to actively obtain a CloudClient
instance from a CloudService
, now the relation between the application and a CloudPublisher or CloudSubscriber instance is represented as an OSGi service reference. Applications should allow the user to modify this reference in configuration, making it easy to switch between different cloud publisher/subscriber instances and different cloud platforms.
Publisher/subscriber instances are now typically instantiated and configured by the end user using the Web UI.
Publisher/subscriber instances are related to a CloudEnpoint
instance using an OSGi service reference encoded in well known configuration property specified in the APIs (CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME
). This allows the user to create those instances in a dedicated section of the Web UI.
Another field in which the current Kura cloud related APIs can be generalized is related to command and control. In the previous model this aspect was covered by the Cloudlet
APIs that are now replaced by RequestHandler
APIs
Legacy Cloudlet
implementations are defined by extending a base class, Cloudlet
, which takes care of handling the invocation of the doGet()
, doPut()
, doPost()
... methods, and of correlating request and response messages. Messages were sent and received through a CloudClient
.
More explicitly, Cloudlet
only works with control topics whose structure is
$EDC/<account-name>/<device-id>/<app-id>/<method>/<resource-path>\n
and also expects the identifier of the sender and the correlation identifier in the KuraPayload
. In the previous model, there is no way for a cloud stack implementor to customize the aspects above, which are hardcoded in the Cloudlet
base class.
The new model delegates these aspects to some component of the cloud stack, and requires applications that want to support command and control to register themselves as RequestHandler
to a RequestHandlerRegistry
instance.
In order to ease porting old applications to the new model, some of the concepts of the old Cloudlet APIs are still present, this can be seen by looking at the RequestHandler
interface definition:
public interface RequestHandler {\n\n public KuraMessage doGet(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException;\n\n public KuraMessage doPut(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException;\n\n public KuraMessage doPost(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException;\n\n public KuraMessage doDel(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException;\n\n public KuraMessage doExec(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException;\n}\n
A RequestHandler
invocation involves the following parameters:
Request parameters:
RequestHandler
method to be calledKuraPayload
wrapped inside the KuraMessage
.List<String>
of positional parameters available under the well known args
key in the provided KuraMessage
properties.Response parameters:
KuraPayload
wrapped inside the returned KuraMessage
.RequestHandler
methods returns without throwing exceptions.RequestHandler
methods throws a KuraException
with KuraErrorCode
== BAD_REQUESTRequestHandler
methods throws a KuraException
with KuraErrorCode
== NOT_FOUNDRequestHandler
methods throws a KuraException
with other error codes.KuraException
thrown by the RequestHandler
methods, if any.KuraException
thrown by the RequestHandler
methods, if any.The parameters above are the same involved in current Cloudlet calls. The request id and requester client id parameters are no longer part of the API, because are related to the to the way Kapua correlates requests and response. In the new API, request and response identifiers are not specified and not forwarded to the Cloudlet, this allows the CloudletService implementation to adopt the platform specific conventions for message correlation.
The Cloudlet parameters must be present in the request and response messages encoded in some format. A user that intends to call a Kura Cloudlet, for example through platform-specific REST APIs must be aware of these parameters. The user must supply request parameters in request message and must be able to extract response data from received message. The actual encoding of these parameters inside the messages depends on the particular platform.
The fact that set of Cloudlet parameters are roughly the same involved in current Cloudlet calls allows existing Cloudlet based applications to continue to work without changes to the protocol.
"},{"location":"cloud-api/overview/#cloud-connection-lifecycle","title":"Cloud Connection lifecycle","text":"CloudEndpoint
instance lifecycle is managed by a CloudConnectionFactory
instance. A cloud connection implementor must register a CloudConnectionFactory
instance in the framework that is responsible of creating and destroying the CloudEndpoint
instances.
The CloudConnectionFactory
will be typically invoked by the Web UI, and is defined as follows:
public interface CloudConnectionFactory {\n\n public static final String KURA_CLOUD_CONNECTION_FACTORY_PID = \"kura.cloud.connection.factory.pid\";\n\n public String getFactoryPid();\n\n public void createConfiguration(String pid) throws KuraException;\n\n public List<String> getStackComponentsPids(String pid) throws KuraException;\n\n public void deleteConfiguration(String pid) throws KuraException;\n\n public Set<String> getManagedCloudConnectionPids() throws KuraException;\n\n}\n
The createConfiguration()
and deleteConfiguration()
methods are responsible of creating/destroying a CloudEndpoint
instance, specified by the provided kura.service.pid
, and all the related services.
The getManagedCloudConnectionPids()
returns the set of kura.service.pid
managed by the factory.
The getStackComponentsPids(String pid)
returns the list of the kura.service.pid
s of the ConfigurableComponent
s that are associated with the CloudEndpoint
with the specified pid. The Web Ui will render the configuration of those components in separated tabs, in the dedicated CloudConnections section.
In order to ease the transition to the new model, legacy APIs like CloudService
and CloudClient
are still supported in Kura 4.0.0, even if deprecated.
The default Kapua oriented CloudService
implementation is still available and can be used by legacy applications without changes. The default CloudService
instance in Kura 4.0 also implements the new CloudEndpoint
and CloudConnectionManager
interfaces.
This guide will illustrate the steps required for configuring an application that uses the new Cloud Connection APIs to publish messages to the Kapua platform.
The involved steps are the following
Open the Cloud Connections section of the Web UI:
Create a new Cloud Connection
Click on the New Connection button
Enter a new unique identifier in the Cloud Connection Service PID field. The identifier must be a valid kura.service.pid
and, in case of a Kapua Cloud Connection, it must start with the org.eclipse.kura.cloud.CloudService-
prefix. A valid identifier can be org.eclipse.kura.cloud.CloudService-KAPUA
. As an alternative it is possible to reconfigure the existing org.eclipse.kura.cloud.CloudService
Cloud Connection.
Configure the MQTTDataTrasport
service.
Click on the MQTTDataTrasport-KAPUA
tab and fill the parameters required for establishing the MQTT connection:
Broker-url
Topic Context Account-Name
Username
Password
Configure the DataService-KAPUA
service.
In order to enable automatic connection, set the Connect Auto-on-startup
parameter to true
Select to the connection to be used from the list.
Click on the New Pub/Sub button.
Select the type of component to be created, from the Available Publisher/Subscriber factories drop down list, in order to create a Publisher select the org.eclipse.kura.cloud.publisher.CloudPublisher
entry.
Enter an unique kura.service.pid identifier in the New Publisher/Subscriber PID field.
Click Apply, you should see the publisher configuration
Select and configure the newly created publisher instance, and then click Apply
Select the application instance configuration
Find the configuration entry that represents a Publisher reference.
Click on the Select available targets link and select the desired Publisher instance to bind to.
Click on Apply
This section provides a guide on connecting an Eclipse Kura\u2122 device to the Amazon AWS IoT platform.
"},{"location":"cloud-platform/kura-aws-cloud/#prerequisites","title":"Prerequisites","text":"The first step involves the registration of the new device on AWS, this operation can be done using the AWS Web Console or with the AWS CLI command line tool, in this guide the Web based console will be used.
"},{"location":"cloud-platform/kura-aws-cloud/#1-access-the-aws-iot-management-console","title":"1. Access the AWS IoT management console.","text":"This can be done by logging in the AWS console and selecting IoT Core from the services list, in the Internet of Things section.
"},{"location":"cloud-platform/kura-aws-cloud/#2-create-a-default-policy-for-the-device","title":"2. Create a default policy for the device.","text":"This step involves creating a default policy for the new device, skip if an existing policy is already available.
Access the main screen of the console and select Secure -> Policies from the left side menu and then press the Create button, in the top right area of the screen.
Fill the form as follows and then press the Create button:
iot:Connect, iot:Publish, iot:Subscribe, iot:Receive, iot:UpdateThingShadow, iot:GetThingShadow, iot:DeleteThingShadow
*
Allow
This will create a policy that allows a device to connect to the platform, publish/subscribe on any topic and manage its thing shadow.
"},{"location":"cloud-platform/kura-aws-cloud/#3-register-a-new-device","title":"3. Register a new device.","text":"Devices on the AWS IoT platform are called things, in order to register a new thing select Manage -> Things from the left side menu and then press the Create button, in the top right section of the screen. Select Create a single thing.
Enter a name for the new device and then press the Next button, from now on kura-gateway
will be used as the device name.
The AWS IoT platform uses SSL mutual authentication, for this reason it is necessary to download a public/private key pair for the device and a server certificate. Click on Create certificate to quickly generate a new certificate for the new device.
Certificates can be managed later on by clicking on Secure -> Certificates, in the left part of the console.
"},{"location":"cloud-platform/kura-aws-cloud/#5-download-the-device-ssl-keys","title":"5. Download the device SSL keys.","text":"You should see a screen like the following:
Download the 3 files listed in the table and store them in a safe place, they will be needed later, also copy the link to the root CA for AWS IoT in order to be able to retrieve it later from the device.
Press the Activate button, and then on Attach a policy.
"},{"location":"cloud-platform/kura-aws-cloud/#6-assign-the-default-policy-to-the-device","title":"6. Assign the default policy to the device.","text":"Select the desired policy and then click on Register thing.
A policy can also be attached to a certificate later on perforiming the following steps:
Enter the device configuration section, by clicking on Manage -> Things and then clicking on the newly created device. Click on Security on the left panel and then click on the certificate entry (it is identified by an hex code), select Policies in the left menu, you should see this screen:
Click on Actions in the top left section of the page and then click on Attach policy, select the default policy previously created and then press the Attach button.
"},{"location":"cloud-platform/kura-aws-cloud/#device-configuration","title":"Device configuration","text":"The following steps should be performed on the device, this guide is based on Kura 3.1.0 version and has been tested on a Raspberry PI 3.
"},{"location":"cloud-platform/kura-aws-cloud/#7-create-a-java-keystore-on-the-device","title":"7. Create a Java keystore on the device.","text":"The first step for using the device keys obtained at the previous step is to create a new Java keystore containing the Root Certificate used by the Amazon IoT platform, this can be done executing the following commands on the device:
sudo mkdir /opt/eclipse/kura/security\n
cd /opt/eclipse/kura/security\n
curl https://www.amazontrust.com/repository/AmazonRootCA1.pem > /tmp/root-CA.pem\n
sudo keytool -import -trustcacerts -alias aws -file /tmp/root-CA.pem -keystore cacerts.ks -storepass changeit\n
If the last command reports that the certificate already exist in the system-wide store type yes
to proceed. The code above will generate a new keystore with changeit
as password, change it if needed.
Open the Kura Web Console and enter select the Settings entry in the left side menu and then click on SSL Configuration, you should see this screen:
Change the Keystore path parameter to /opt/eclipse/kura/security/cacerts.ks
if needed.
Change the settings in the form to match the screen above, set Default protocol to TLSv1.2, enter changeit
as Keystore Password (or the password defined at step 7).
Warning
Steps from 8.2 to 8.6 will not work on Kura 3.2.0 due to a known issue. On this version, private key and device certificate need to be manually added to the keystore using the command line. If you are running Kura 3.2.0, proceed with step 8.7.
Open the Kura Web Console and enter select the Settings entry in the left side menu and then click on Device SSL Certificate, you should see this screen:
Enter aws-ssl
in the Storage Alias field.
The private key needs to be converted to the PKCS8 format, this step can be performed executing the following command on a Linux or OSX based machine:
openssl pkcs8 -topk8 -inform PEM -outform PEM -in xxxxxxxxxx-private.pem.key -out outKey.pem -nocrypt\n
where xxxxxxxxxx-private.pem.key
is the file containing the private key downloaded at step 4.
Paste the contents of the obtained outKey.pem
in the \"Private Key\" field.
Paste the contents of xxxxxxxxxx-certificate.pem.crt
in the Certificate field.
You should see a screen like this
Click the Apply button to confirm.
Kura 3.2.0 only - manually import device certificate and private key into keystore.
On the host machine, open a terminal window in the folder containing the files downloaded at step 5 and execute the following command:
openssl pkcs12 -export -in xxxxxxxxxx-certificate.pem.crt -inkey xxxxxxxxxx-private.pem.key -name aws-ssl -out aws-ssl.p12\n
where xxxxxxxxxx-certificate.pem.crt
is the original certificate downloaded from AWS and xxxxxxxxxx-private.pem.key
is the private key.
The command will ask for a password, define a new password.
Copy the obtained aws-ssl.p12
file to the device into the /tmp
folder using scp:
scp ./aws-ssl.p12 pi@<device-address>:/tmp\n
Replacing <device-address>
with the hostname or ip address of the device.
Open a ssh connection to the device and enter the following command:
sudo keytool -importkeystore -deststorepass changeit -destkeystore /opt/eclipse/kura/security/cacerts.ks -srckeystore /tmp/aws-ssl.p12 -srcstoretype PKCS12\n
The command will ask for a password, enter the password defined when creating the aws-ssl.p12
file.
Restart Kura to reload the keystore.
Click on Cloud Connections in the left panel, and setup a new cloud connection
Click on the New Connection button at the top of the page and set the following parameters in the dialog:
org.eclipse.kura.cloud.CloudService
org.eclipse.kura.cloud.CloudService-AWS
Press the Create button to confirm and then select the newly created CloudService instance from the list.
Set the broker URL in the MqttDataTransport-AWS tab, it can be obtained from the AWS IoT Web Console clicking on the Settings entry in the bottom left section of the page, the URL will look like the following:
a1rm1xxxxxxxxx.iot.us-east-1.amazonaws.com\n
The mqtts protocol must be used, the value for the broker-url field derived from the URL above is the following:
mqtts://a1rm1xxxxxxxxx.iot.us-east-1.amazonaws.com:8883/\n
Clear the value of the username and password fields.
Set a value for the topic.context.account-name and client-id.
Assign an arbitrary account name to topic.context.account-name (for example aws-test
), this will be used by the CloudClient instances for building the topic structure.
Enter the thing name in the client-id field (in this example kura-gateway
).
In order for the previously added keys to be used for the SSL connection with the broker enter the Storage Alias defined in step 8.2 (e.g aws-ssl
) as value for the ssl.certificate.alias field.
The setting lwt.topic under MqttDataTransport-AWS needs to be updated as well by entering a value not containing the $ character. This is required because of the fact that AWS IoT does not support topic names starting with $ (except for the $aws/ hierarchy).
Press the Apply button in the top left section to commit the changes to the MqttDataTransport-AWS.
Enter a name without the $ character for the topic.control-prefix setting in the CloudService-AWS tab, for example aws-control
.
The Kura CloudService uses some well-known topics to allow remote device management and to report device state information, this features are not supported by default by AWS IoT, the following settings can be applied in the CloudService-AWS tab in order to avoid sending unnecessary messages:
false
false
false
Click the Apply button to save the changes.
Make sure the AWS CloudService instance is selected from the list in the top section of the page and click on the Connect button, if the connection to AWS IoT platform succeeds the Status of the instance will be reported as Connected.
"},{"location":"cloud-platform/kura-azure/","title":"Azure IoT Hub\u2122 platform","text":"Starting from release 3.0, Eclipse Kura can connect to the Azure IoT Hub using the MQTT protocol. When doing so, Kura applications can send device-to-cloud messages. More information on the Azure IoT Hub and its support for the MQTT protocol can be found here. This document outlines how to configure and connect a Kura application to the Azure IoT Hub.
"},{"location":"cloud-platform/kura-azure/#get-azure-iot-hub-information","title":"Get Azure IoT Hub information","text":"In order to properly configure Kura to connect to IoT Hub, some information are needed. You will need the hostname of the Azure IoT Hub, referred below as {iothubhostname}
, the Id and the SAS Token of the device, referred as {device_id}
and {device_SAS_token}
. The hostname is listed on the \"Overview\" tab on the IoT Hub main page, while the device ID is shown on the \"Device Explorer\" tab. Finally, the SAS token can be generated using the iothub-explorer application that can be found here. To install the application, type on a shell:
npm install -g iothub-explorer\n
Then start a new session on your IoT Hub instance (it will expire in 1 hour):
iothub-explorer login \"{your-connection-string}\"\n
where {your-connection-string}
is the connection string of your IoT Hub instance. It can be found on the \"Shared access policies\" tab under \"Settings\". Select the \"iothubowner\" policy and a tab will appear with the \"Connection string\u2014primary key\" option. Then list your devices:
iothub-explorer list\n
and get the SAS token for the {device-name}
device:
iothub-explorer sas-token {device-name}\n
Be aware that the SAS token will expire in 1 hour by default, but using \"-d\" option it is possible to set a custom expiration time.
"},{"location":"cloud-platform/kura-azure/#ssl-certificates","title":"SSL certificates","text":"In order to connect to your IoT Hub instance, Kura should trust the remote broker through a SSL certificate. The simpler way to get the IotHub certificate is to run the following command on a shell:
openssl s_client -showcerts -tls1 -connect {iothubhostname}:8883\n
The result is the SSL certificate chain. Copy all the certificates in the format:
-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n
and paste them in to the \"Server SSL Certificate\" tab under \"Settings\" in Kura. Then click the Apply button and restart Kura to update the keystore.
"},{"location":"cloud-platform/kura-azure/#configuring-a-kura-cloud-stack-for-azure-iot-hub","title":"Configuring a Kura Cloud Stack for Azure IoT Hub","text":"The Kura Gateway Administrative Console exposes all services necessary to configure a connection to the Azure IoT Hub. You can follow the steps outlined below to configure the connection to the Azure IoT Hub.
The first step is to create a new Kura Cloud stack. From the Kura Gateway Administrative Console:
org.eclipse.kura.cloud.CloudService
as the Cloud Connection Factory PIDorg.eclipse.kura.cloud.CloudService-Azure
Now review and update the configuration of each Kura Cloud stack component as outline below.
Modify the service configuration parameters as follows:
broker-url - defines the URL of the Azure IoT MQTT broker. The URL value should be set as mqtts://{iothubhostname}:8883/
Note
An SSL connection (mqtts on port 8883) is required to connect to Azure IoT Hub\u2122.
topic.context.account-name - insert devices
as the MQTT topic prefix for the device-to-cloud and cloud-to-device messages
{iothubhostname}/{device_id}
as username for the MQTT connectionpassword - insert {device_SAS_token}
as password for the MQTT connection
Note
The format of the SAS Token is like:
SharedAccessSignature sig={signature-string}&se={expiry}&sr={URL-encoded-resourceURI}\n
client-id - insert {device_id}
as Client ID for the MQTT connection
true
#account-name/#client-id/messages/events/LWT
You can keep the default values of the remaining parameters, so save your changes by clicking the Apply button. A screen capture of the MqttDataTransport configuration is shown below.
"},{"location":"cloud-platform/kura-azure/#dataservice","title":"DataService","text":"The majority of default settings in the DataService can be left unchanged. A screen capture of the DataService configuration is shown below.
In order for Kura to connect to Azure IoT Hub on startup, the connect.auto-on-startup option must be set to true. If this value is changed from false to true, Kura will immediately begin the connection process. It is recommended that the CloudService and MqttDataTransport are configured before setting the connect.auto-on-startup option to true.
Note
Changing the value of connect.auto-on-startup from true to false will not disconnect the client from the broker. This setting simply implies that Kura will not automatically connect on the next start of Kura.
"},{"location":"cloud-platform/kura-azure/#cloudservice","title":"CloudService","text":"The default settings for the CloudService should be modified as follow to allow a connection to Azure IoT Hub .
devices
as the MQTT topic prefix for the device-to-cloud and cloud-to-device messagesfalse
to avoid compression of the message payloadsfalse
to avoid sending additional messages on GPS position lockfalse
to avoid sending additional messages on cellular modem updatefalse
to avoid subscriptions on Kura control topics for cloud-to-deviceSimple JSON
The screen capture shown below displays the default settings for the CloudService.
"},{"location":"cloud-platform/kura-azure/#how-to-connect-and-disconnect-from-the-cloud-platform","title":"How to connect and disconnect from the cloud platform","text":"The status panel can be used to manually connect or disconnect the client while Kura is running. The main button toolbar has a connect and disconnect button that may be used to control connectivity.
Note
Connecting or disconnecting the client via the status panel has no impact on Kura automatically connecting at startup. This capability is only controlled via the connect.auto-on-startup DataService setting.
"},{"location":"cloud-platform/kura-azure/#kura-application-connecting-to-azure-iot-hub","title":"Kura Application Connecting to Azure IoT Hub","text":"The Kura example publisher can be used to publish to the IoT Hub. The example configuration should be modified as follows.
org.eclipse.kura.cloud.CloudService-Azure
in this tutorialmessages
as application idevents/
as publish topicThis configuration allows the publication on the default messages/events
endpoint on the IoT Hub\u2122.
Everyware Cloud provides an easy mechanism for connecting cloud-ready devices to IT systems and/or applications; therefore, connecting to Everyware Cloud is an important step in creating and maintaining a complete M2M application. Information on Everyware Cloud and its features can be found here. This document outlines how to connect to Everyware Cloud using the Kura Gateway Administrative Console.
"},{"location":"cloud-platform/kura-ec-cloud/#using-the-kura-gateway-administrative-console","title":"Using the Kura Gateway Administrative Console","text":"The Kura Gateway Administrative Console exposes all services necessary for connecting to Everyware Cloud. The reference links listed below outline each service involved in the Everyware Cloud connection. It is recommended that each section be reviewed.
The default settings for the CloudService are typically adequate for connecting to Everyware Cloud. The screen capture shown below displays the default settings for the CloudService. For details about each setting, please refer to CloudService.
Warning
The \"Simple JSON\" payload encoding is not supported by Everyware Cloud. Use the default \"Kura Protobuf\" encoding instead.
"},{"location":"cloud-platform/kura-ec-cloud/#dataservice","title":"DataService","text":"The majority of default settings in the DataService can be left unchanged. A screen capture of the DataService configuration is shown below. For complete details about the DataService configuration parameters, please refer to DataService.
In order for Kura to connect to Everyware Cloud on startup, the connect.auto-on-startup option must be set to true
. If this value is changed from false
to true
, Kura will immediately begin the connection process. It is recommended that the CloudService and MqttDataTransport are configured before setting the connect.auto-on-startup option to true
.
Note
Changing the value of connect.auto-on-startup from true
to false
will not disconnect the client from the broker. This setting simply implies that Kura will not automatically connect on the next start of Kura.
While the majority of default settings in the MqttDataTransport can be left unchanged, the following parameters must be modified:
mqtt://broker-sbx.everyware.io:1883
account-name
username
.Note
When connecting to Everyware Cloud, the username must have proper permissions. Information on users and permissions can be found here.
For complete details about the MqttDataTransport configuration parameters, please refer to MqttDataTransport.
"},{"location":"cloud-platform/kura-ec-cloud/#connectdisconnect","title":"Connect/Disconnect","text":"The status panel can be used to manually connect or disconnect the client while Kura is running. The main button toolbar has a connect and disconnect button that may be used to control connectivity.
Note
Connecting or disconnecting the client via the status panel has no impact on Kura automatically connecting at startup. This capability is only controlled via the connect.auto-on-startup DataService setting.
"},{"location":"cloud-platform/kura-hono/","title":"Eclipse Hono\u2122 platform","text":"Eclipse Hono\u2122 provides remote service interfaces for connecting large numbers of IoT devices to a back end and interacting with them in a uniform way regardless of the device communication protocol. More information can be found here. This document outlines how to connect to Eclipse Hono using the Kura Gateway Administrative Console.
"},{"location":"cloud-platform/kura-hono/#using-the-kura-gateway-administrative-console","title":"Using the Kura Gateway Administrative Console","text":"The Kura Gateway Administrative Console exposes all services necessary for connecting to Eclipse Hono. First of all, in the Cloud Connections section, a new Hono-enabled connection needs to be setup.
From the Cloud Connections section,
the user needs to create a new connection:
by specifying a valid PID:
The result should be like the one depicted in the following image:
The reference links listed below outline each service involved in the cloud connection. It is recommended that each section be reviewed.
The default settings for the CloudService are typically adequate for connecting to a Hono instance. The screen capture shown below displays the default settings for the CloudService. For details about each setting, please refer to CloudService.
"},{"location":"cloud-platform/kura-hono/#dataservice","title":"DataService","text":"The majority of default settings in the DataService can be left unchanged. A screen capture of the DataService configuration is shown below. For complete details about the DataService configuration parameters, please refer to DataService.
In order for Kura to connect to Eclipse Hono on startup, the connect.auto-on-startup option must be set to true
. If this value is changed from false
to true
, Kura will immediately begin the connection process. It is recommended that the CloudService and MqttDataTransport are configured before setting the connect.auto-on-startup option to true
.
Note
Changing the value of connect.auto-on-startup from true
to false
will not disconnect the client from the broker. This setting simply implies that Kura will not automatically connect on the next start of Kura.
While the majority of default settings in the MqttDataTransport can be left unchanged, the following parameters must be modified:
mqtt://broker-url:1883
account-name
username
.For complete details about the MqttDataTransport configuration parameters, please refer to MqttDataTransport.
"},{"location":"cloud-platform/kura-hono/#connectdisconnect","title":"Connect/Disconnect","text":"The status panel can be used to manually connect or disconnect the client while Kura is running. The main button toolbar has a connect and disconnect button that may be used to control connectivity.
Note
Connecting or disconnecting the client via the status panel has no impact on Kura automatically connecting at startup. This capability is only controlled via the connect.auto-on-startup DataService setting.
"},{"location":"cloud-platform/kura-kapua/","title":"Eclipse Kapua\u2122 platform","text":"Eclipse Kapua\u2122 is a modular platform providing the services required to manage IoT gateways and smart edge devices. Kapua provides a core integration framework and an initial set of core IoT services including a device registry, device management services, messaging services, data management, and application enablement. More information can be found here. This document outlines how to connect to Eclipse Kapua using the Kura Gateway Administrative Console.
"},{"location":"cloud-platform/kura-kapua/#using-the-kura-gateway-administrative-console","title":"Using the Kura Gateway Administrative Console","text":"The Kura Gateway Administrative Console exposes all services necessary for connecting to Eclipse Kapua. The reference links listed below outline each service involved in the cloud connection. It is recommended that each section be reviewed.
The default settings for the CloudService are typically adequate for connecting to a Kapua instance. The screen capture shown below displays the default settings for the CloudService. For details about each setting, please refer to CloudService.
Warning
The \"Simple JSON\" payload encoding is not supported by Kapua. Use the default \"Kura Protobuf\" encoding instead.
"},{"location":"cloud-platform/kura-kapua/#dataservice","title":"DataService","text":"The majority of default settings in the DataService can be left unchanged. A screen capture of the DataService configuration is shown below. For complete details about the DataService configuration parameters, please refer to DataService.
In order for Kura to connect to Eclipse Kapua on startup, the connect.auto-on-startup option must be set to true
. If this value is changed from false
to true
, Kura will immediately begin the connection process. It is recommended that the CloudService and MqttDataTransport are configured before setting the connect.auto-on-startup option to true
.
Note
Changing the value of connect.auto-on-startup from true
to false
will not disconnect the client from the broker. This setting simply implies that Kura will not automatically connect on the next start of Kura.
While the majority of default settings in the MqttDataTransport can be left unchanged, the following parameters must be modified:
account-name
username
.For complete details about the MqttDataTransport configuration parameters, please refer to MqttDataTransport.
"},{"location":"cloud-platform/kura-kapua/#connectdisconnect","title":"Connect/Disconnect","text":"The status panel can be used to manually connect or disconnect the client while Kura is running. The main button toolbar has a connect and disconnect button that may be used to control connectivity.
Note
Connecting or disconnecting the client via the status panel has no impact on Kura automatically connecting at startup. This capability is only controlled via the connect.auto-on-startup DataService setting.
"},{"location":"cloud-platform/kura-sparkplug/","title":"Eclipse Sparkplug\u00ae Cloud Connector","text":"The org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider
package provides a Eclipse Kura Cloud Connection that implements the Eclipse Sparkplug\u00ae v3.0.0 specification.
Minimum requirements
This addon is compatible with Kura 5.2+.
"},{"location":"cloud-platform/kura-sparkplug/#introduction-to-eclipse-sparkplug","title":"Introduction to Eclipse Sparkplug","text":"from Eclipse Sparkplug
Sparkplug is an open software specification that provides MQTT clients the framework to seamlessly integrate data from their applications, sensors, devices, and gateways within the MQTT Infrastructure. It is specifically designed for use in Industrial Internet of Things (IIoT) architectures to ensure a high level of reliability and interoperability.
The specification aims fulfill the following 3 goals:
To achieve that, the Eclipse Sparkplug specification defines an architecture (see picture below) and 4 main actors:
Image from https://sparkplug.eclipse.org/specification/version/3.0/documents/sparkplug-specification-3.0.0.pdf
The main principles upon which the Specification is based on can be summarized as follows:
Connection Persistence: with the mechanisms above, the connection does not need to be persistent. For example, an Edge Node that disconnects gracefully with a MQTT DISCONNECT packet will not be seen as \"dead\" from the host application because no death certificate has been triggered (Will messages are sent only on failures). Hence, the Edge Node can implement a logic where it remains connected only during the timeframe needed for sending the new data.
Warning
This Cloud Connection maintains a persistent connection to the MQTT server.
All clients using the specification must adhere to the following topic namespace:
namespace/group_id/message_type/edge_node_id/[device_id]\n
where:
namespace
: defines the structure of the remaining elements and the encoding for the payload. With Sparkplug v3.0.0 the namespace to utilize is spBv1.0
.group_id
: some Edge Nodes can be related to each other identifying a group (for example, Edge Nodes in a given plant). This element is the identifier for the group.message_type
: defines how to interpret and handle the payload. It encapsulates the semantic of the message and can be one of the following elements:NBIRTH
/NDEATH
: Edge Node birth and death certificates.DBIRTH
/DDEATH
: Device birth and death certificates.NDATA
/DDATA
: message containing data reported by the Edge Node or Device.NCMD
/DMCD
: message containing commands for the Edge Node or Device.STATE
: message from the Primary Host Application indicating the state (offline/online) of the main consumer.edge_node_id
: the identifier for the Edge Node.device_id
(optional): the identifier for the Device. Must be unique under the same edge_node_id
and must be always present on messages belonging to Devices (D- type messages).The combination of group_id
and edge_node_id
must be unique and is called Edge Node Descriptor.
Tip
It is advised to have group_id
, edge_node_id
, and device_id
as small but as descriptive as possible, for better efficiency.
This introduction will focus more on the Edge Node and Device, as they are of more interest for this Cloud Connection.
"},{"location":"cloud-platform/kura-sparkplug/#session-management","title":"Session Management","text":"The session estabilishment procedure ensures the Edge Node to be subscribed to command-type messages for receiveing commands from the Host Application.
An Edge Node can (optionally, but incouraged) specify to be aware of a primary host application state and, in such case, it needs to subscribe to the relative STATE messages. The Edge Node will send the birth certificate (and thus completing the session init procedure) only after receiving the STATE message denoting the Primary Host Application is online. After connection, if the Edge Node receives a STATE message denoting the Primary Host Application is offline, it must restart the session estabilishment procedure.
On connection, the Edge Node sets a MQTT Will message containing a NDEATH certificate. Doing so, if the MQTT broker does not receive any communication within the Keep Alive period (client lost connection), it will send the Edge Node NDEATH certificate on all subscribers. A birth/death sequence number bdSeq
is maintained in the Edge Node to match NBIRTH with NDEATH messages in the Host Application. Each bdSeq
in the NDEATH message is matched with the corresponding bdSeq
of the previous NBIRTH message. This allows the Host Application tracking the state of the Edge Nodes and mark not up-to-date metrics as STALE.
A Device can send a device DBIRTH message after a Edge Node NBIRTH has been sent. The DBIRTH message contains all the metrics that the device will ever report on. If a new metric is added or an existing one removed, then the Device session needs to be re-estabilished. If the Edge Node looses the connection to some of its Devices, then it needs to send a Device DDEATH certificate on his behalf. The data-consuming Host Application will then mark that particular Device as offline and mark its metrics as STALE. Once the session is estabilished, the Device can publish the changed metrics using the DDATA message type.
"},{"location":"cloud-platform/kura-sparkplug/#multiple-mqtt-server-topologies","title":"Multiple MQTT Server Topologies","text":"A Primary Host Application must publish its STATE message every time it connects to the MQTT broker. This ensures the Edge Nodes to be aware of its status as long as they remain connected to the MQTT server.
At any point in time, an Edge Node can be connected to at most one MQTT server. If multiple MQTT servers are defined each time the Edge Node receives an offline STATE message from its Primary Host Application it needs to terminate the session and estabilish a new one with the next MQTT broker.
"},{"location":"cloud-platform/kura-sparkplug/#further-resources","title":"Further Resources","text":"The cloud endpoint layer allows to attach CloudPublisher
s and CloudSubscriber
s to publish/subscribe messages on Sparkplug topics.
Each CloudPublisher
attached to this cloud connection acts as a Sparkplug Device. The corresponding configuration is shown in the picture below.
The parameter specified as device.id
will dictate the Sparkplug device identifier used to publish messages from this cloud publisher. A device DBIRTH
message is immediately sent from this publisher when the first publish occurs or when a the set of published metrics is changed. The subsequent messages will be published as Sparkplug device data (DDATA
message type).
The Sparkplug Device implemented by this publisher does not support the following features (optional in the Eclipse Sparkplug specification):
tck-id-operational-behavior-device-ddeath
: Device death messages (DDEATH
message type) since the usual way to publish data from the Wire Graph using a WireAsset attached to a CloudPublisher has no implementation for reporting error states (see WireAsset.onWireReceive
)tck-id-payloads-alias-uniqueness
: Sparkplug aliases for metricstck-id-message-flow-device-dcmd-subscribe
: writing to outputs, hence it will not subscribe to device command messages (DCMD
message type)The payload of DDATA
message will be encoded using the Sparkplug B Protobuf definition converting the KuraPayload
into Sparkplug payload as follows:
Metrics from KuraPayload.metric()
become Sparkplug metrics. Only the name, timestamp, datatype and value components are added. The timestamp is set to the publishing instant. The datatype is inferred from the Java type as follows:
Boolean
DataType.Boolean
byte[]
DataType.Bytes
Double
DataType.Double
Float
DataType.Float
Byte
DataType.Int8
Short
DataType.Int16
Integer
DataType.Int32
Long
DataType.Int64
String
DataType.String
Date
DataType.DateTime
BigInteger
DataType.UInt64
All other Java types will cause the application to throw an Exception.
KuraPayload.getBody()
, if non null, will be copied into the body of the Sparkplug payload
KuraPayload.getPosition()
, if not null, will be used to create the following metrics from the KuraPosition
object, if the value in there is not null (with the corresponding Sparkplug data types):
DataType.Double
DataType.Double
DataType.Double
DataType.Double
DataType.Double
DataType.Int32
DataType.Int32
DataType.Double
DataType.DateTime
KuraPayload.getTimestamp()
, if not null, it will be used as the timestamp metric of the Sparkplug payload
This cloud connections allows creating a Cloud Subscriber that will subscribe to a generic set of topics. The configuration is shown in the picture below.
It is assumed that the payloads received by this Cloud Connection are encoded using the Sparkplug B Protobuf definition. Users of this Cloud Subscriber should expect to receive KuraMessage
s containing a KuraPayload
such that:
KuraPayload.setBody()
seq
All Sparkplug Metrics are converted into Kura metrics with the same name and the following conversion rules:
Sparkplug ValueCase Java TypeBoolean
boolean
Bytes
byte[]
Dataset
byte[]
Double
double
Extension
byte[]
Float
float
Integer
int
Long
long
String
String
Template
byte[]
default null
The metric timestamp is not supported in Eclipse Kura, therefore this information is lost at conversion.
The DataService
layer used in this component is the org.eclipse.kura.data.DataService
implementation. Please refer to the Data Service Configuraion page for further details.
The Sparkplug Data Transport layer bridges the incoming requests to the underlying Eclipse Paho MQTT v3.1.1 client following the Sparkplug specification. In particular, the Data Transport Layer ensures the following.
true
, restarts the session estabilishment procedure without sending an MQTT CONNECT packet (client connection is not closed, only BIRTH messages are re-sent).The Sparkplug Data Transport layer is configured to wait for a random period of time between 0sec and 5sec before each connection attempt. This is to ensure that, on large deployments, the target MQTT servers and Host Applications will dilute session estabilishment requests by some margin. This behavior is not part of the Sparkplug specification.
This cloud connection supports SSL connections to the connecting broker. The option SslManagerService.target allows, as an OSGi target filter, to specify the pid of the SslManagerService
instance to use for creating SSL connections for broker URIs that use the ssl://
protocol. The default socket factory is used otherwise.
As of 2.1.0 Kura provides a set of different ways to implement an application backed by Camel:
Kura provides a special \"Kura cloud endpoint\" which allows to publish or subscribe to the Kura Cloud API. The default component name for this component is kura-cloud
but it may be overridden in the following use cases.
The default component will only be registered once the default Kura Cloud API is registered with OSGi. This instance is registered with the OSGi property kura.service.pid=org.eclipse.kura.cloud.CloudService
.
If you want to publish to a different cloud service instance you can either manually register a new instance of this endpoint, or e.g. use a functionality like the Simple XML router provides: also see selecting a cloud service.
"},{"location":"cloud-platform/apache-camel-integration/kura-camel-app/#endpoint-uri","title":"Endpoint URI","text":"The URI syntax of the endpoint is (assuming the default component name): kura-cloud:appid/topic
. Where appid
is the application ID registered with the Cloud API and topic
is the topic to use.
The following URI parameters are supported by the endpoint:
Name Type Default DescriptionapplicationId
String From URI path The application ID used with the Cloud API topic
String From URI path The default topic name to publish/subscribe to when no header value is specified qos
Integer 0 The QoS value when publishing to MQTT retain
Boolean false The default retain flag when publishing to MQTT priority
Integer 5 The default priority value control
Boolean false Whether to publish/subscribe on the control or data topic hierarchy deviceId
String empty The default device ID when publishing/subscribing to control topics The following header fields are supported. If a value is not set when publishing it is taken from the endpoint configuration:
Name Type DescriptionCamelKuraCloudService.topic
String The name of the topic to publish to or from which the message was received CamelKuraCloudService.qos
Integer The QoS to use when publishing to MQTT CamelKuraCloudService.retain
Boolean The value of the retain flag when publishing to MQTT CamelKuraCloudService.control
Boolean Whether to publish/subscribe on the control or data topic hierarchy CamelKuraCloudService.deviceId
String The device ID when publishing to control topics"},{"location":"cloud-platform/apache-camel-integration/kura-camel-app/#cloud-to-cloud-messaging","title":"Cloud to cloud messaging","text":"As already described, header values override the endpoint settings. This allows for a finer grained control with Camel messaging. However this can cause unexpected behavior when two Cloud API endpoints are bridged. Camel can received from a Cloud endpoint but also publish to it. Now it is possible to write Camel routes with exchange messages, receiving from one Cloud API, pushing to another.
------------------- -------------------\n| Cloud Service A | <---> | Cloud Service B |\n------------------- -------------------\n
Which could result in a Camel route XML like:
<route id=\"bridgeLocalToRemote\">\n <from uri=\"local-cloud:sensor/sensor1\" />\n <to uri=\"upstream-cloud:gateway1/all-sensors\" />\n</route>\n
However the Consumer (from) would set the topic header value with the topic name it received the message from. And the Producer (to) would get its topic from the URI overriden by that header value.
In order to fix this behavior the header field has to be cleared before publishing:
<route id=\"bridgeLocalToRemote\">\n <from uri=\"local-cloud:sensor/sensor1\" />\n <removeHeaders pattern=\"CamelKuraCloudService.topic\"/>\n <to uri=\"upstream-cloud:gateway1/all-sensors\" />\n</route>\n
"},{"location":"cloud-platform/apache-camel-integration/kura-camel-app/#simple-xml-routes","title":"Simple XML routes","text":"Eclipse Kura 2.1.0 introduces a new \"out-of-the-box\" component which allows to configure a set of XML based routes. The component is called \"Camel XML router\" and can be configured with a simple set of XML routes.
The following example logs all messages received on the topic foo/bar
to a logger named MESSAGE_FROM_CLOUD
:
<routes xmlns=\"http://camel.apache.org/schema/spring\">\n <route id=\"cloudConsumer\">\n <from uri=\"kura-cloud:foo/bar\"/>\n <to uri=\"log:MESSAGE_FROM_CLOUD\"/>\n </route>\n</routes>\n
But it is also possible to generate data and push to upstream to the cloud service:
<route id=\"route1\">\n <from uri=\"timer:foo\"/>\n <setBody>\n <method ref=\"payloadFactory\" method=\"create('random',${random(10)})\"/>\n </setBody>\n <bean ref=\"payloadFactory\" method=\"append('foo','bar')\"/>\n <to uri=\"stream:out\"/>\n <to uri=\"kura-cloud:myapp/test\"/>\n</route>\n
This example to run a timer named \"foo\" every second. It uses the \"Payload Factory\" bean, which is pre-registered, to create a new payload structure and then append a second element to it.
The output is first sent to a logger and then to the cloud source.
"},{"location":"cloud-platform/apache-camel-integration/kura-camel-app/#defining-dependencies-on-components","title":"Defining dependencies on components","text":"It is possible to use the Web UI to define a list of Camel components which must be present in order for this configuration to work. For example if the routes make use of the \"milo-server\" adapter for providing OPC UA support then \"milo-server\" can be added and the setup will wait for this component to be registered with OSGi before the Camel context gets started.
The field contains a list of comma separated component names: e.g. milo-server, timer, log
It is also possible to define a map of cloud services which will be available for upstream connectivity. This makes use of Kura's \"multi cloud client\" feature. CloudService instances will get mapped from either a Kura Service PID (kura.service.pid
, as shown in the Web UI) or a full OSGi filter. The string is a comma seperated, key=value
string, where the key is the name of the Camel cloud the instance will be registered as and the value is the Kura service PID or the OSGi filter string.
For example: cloud=org.eclipse.kura.cloud.CloudService, cloud-2=foobar
If a standard XML route configuration is not enough then it is possible to use XML routes in combination with a custom OSGi bundle or a Java DSL based Camel approach. For this to work a Kura development setup is required, please see Getting started for more information.
The implementation of such Camel components follow the standard Kura guides for developing components, like, for example, the ConfigurableComponent
pattern. This section only describes the Camel specifics.
Of course it is also possible to follow a very simple approach and directly use the Camel OSGi functionalities like org.apache.camel.core.osgi.OsgiDefaultCamelContext
.
Note
Kura currently doesn't support the OSGi Blueprint approach
Kura support for Camel is split up in two layers. There is a more basic support, which helps in running a raw Camel router. This is CamelRunner
which is located in the package org.eclipse.kura.camel.router
. And then there are a few abstract basic components in the package org.eclipse.kura.camel.component
which help in creating Kura components based on Camel.
The base classes in org.eclipse.kura.camel.component
are intended to help creating new OSGi DS components base on Camel.
For an XML based approach which can be configured through the Kura ConfigurationService
the base class AbstractXmlCamelComponent
can be used. The constructor expectes the name of a property which will contain the Camel XML router information when it gets configured through the configuration service. It will automatically parse and apply the Camel routes.
The method void beforeStart(CamelContext camelContext)
may be used in order to configure the Camel context before it gets started.
Every time the routes get updated using the modified(Map<String, Object>)
method, the route XML will be re-parsed and routes will be added, removed or updated according to the new XML.
In order to create a Java DSL based router setup the base class AbstractJavaCamelComponent
may be used, which implements and RouteBuilder
class, a simple setup might look like:
import org.eclipse.kura.camel.component.AbstractJavaCamelComponent;\n\nclass MyRouter extends AbstractJavaCamelComponent {\n public void configure() throws Exception {\n from(\"direct:test\")\n .to(\"mock:test\");\n }\n}\n
"},{"location":"cloud-platform/apache-camel-integration/kura-camel-app/#using-the-camelrunner","title":"Using the CamelRunner","text":"The CamelRunner
class is not derived from any OSGi or Kura base class and can be used in scenarios where more flexibility is required. It allows to define a set of pre-requisites for the Camel context. It is for example possible to define a dependency on a Kura cloud service instance and a Camel component provider. Once the runner is started it will listen for OSGi services resolving those dependencies and then starting up the Camel context. The following example shows how to set up a Camel context using the CamelRunner
:
// create a new camel Builder\n\nBuilder builder = new CamelRunner.Builder();\n\n// add service dependency\n\nbuilder.cloudService(\"kura.service.pid\", \"my.cloud.service.pid\");\n\n// add Camel component dependency to 'milo-server'\n\nbuilder.requireComponent(\"milo-server\");\n\nCamelRunner runner = builder.build();\n\n// set routes\n\nrunner.setRoutes ( new RouteBuilder() {\n public void configure() throws Exception {\n from(\"direct:test\")\n .to(\"mock:test\");\n }\n} );\n\n// set routes\n\nrunner.start ();\n
It is also possible to later update routes with a call to setRoutes
:
// maybe update routes at a later time\n\nrunner.setRoutes ( /* different routes */ );\n
"},{"location":"cloud-platform/apache-camel-integration/kura-camel-app/#examples","title":"Examples","text":"The following examples can help in getting started.
"},{"location":"cloud-platform/apache-camel-integration/kura-camel-app/#kura-camel-example-publisher","title":"Kura Camel example publisher","text":"The Camel example publisher (org.eclipse.kura.example.camel.publisher
) can be used as an reference for starting. The final OSGi bundle can be dropped into a Kura application an be started. It allows to configure dynamically during runtime and is capable of switching CloudService instances dynamically.
The Camel quickstart project (org.eclipse.kura.example.camel.quickstart
) shows two components, Java and XML based, working together. The bundle can also be dropped into Kura for testing.
The Camel quickstart project (org.eclipse.kura.example.camel.aggregation
) shows a simple data aggregation pattern with Camel by processing data and publishing the result.
The default way to create a new cloud service instance backed by Camel is to use the new Web UI for cloud services. A new cloud service instance of the type org.eclipse.kura.camel.cloud.factory.CamelFactory
has to be created. In addition to that a set of Camel routes have to be provided.
The interface with the Kura application is the Camel vm
component. Information set \"upstream\" from the Kura application can be received by the Camel cloud service instance of the following endpoint vm:camel:example
. Where camel
is the application id and example
is the topic.
The following code snippet writes out all of the Kura payload structure received on this topic to the logger system:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<routes xmlns=\"http://camel.apache.org/schema/spring\">\n\n <route id=\"camel-example-topic\">\n <from uri=\"vm:camel:example\"/>\n <split>\n <simple>${body.metrics().entrySet()}</simple>\n <setHeader headerName=\"item\">\n <simple>${body.key()}</simple>\n </setHeader>\n <setBody>\n <simple>${body.value()}</simple>\n </setBody>\n <toD uri=\"log:kura.data.${header.item}\"/>\n </split>\n </route>\n\n</routes>\n
The snippet splits up the incoming KuraPayload structure and creates a logger called kura.data.<metric>
for each metric and writes out the actual value to it. The output in the log file should look like:
2016-11-14 16:14:34,539 [Camel (camel-10) thread #18 - vm://camel:example] INFO k.d.intValue - Exchange[ExchangePattern: InOnly, BodyType: Long, Body: 19]\n2016-11-14 16:14:34,566 [Camel (camel-10) thread #18 - vm://camel:example] INFO k.d.doubleValue - Exchange[ExchangePattern: InOnly, BodyType: Double, Body: 10.226808617581144]\n2016-11-14 16:14:35,575 [Camel (camel-10) thread #18 - vm://camel:example] INFO k.d.intValue - Exchange[ExchangePattern: InOnly, BodyType: Long, Body: 19]\n2016-11-14 16:14:35,602 [Camel (camel-10) thread #18 - vm://camel:example] INFO k.d.doubleValue - Exchange[ExchangePattern: InOnly, BodyType: Double, Body: 10.27218775669447]\n2016-11-14 16:14:36,539 [Camel (camel-10) thread #18 - vm://camel:example] INFO k.d.intValue - Exchange[ExchangePattern: InOnly, BodyType: Long, Body: 19]\n2016-11-14 16:14:36,567 [Camel (camel-10) thread #18 - vm://camel:example] INFO k.d.doubleValue - Exchange[ExchangePattern: InOnly, BodyType: Double, Body: 10.314456684208022]\n
"},{"location":"cloud-platform/apache-camel-integration/kura-camel/","title":"Apache Camel\u2122 integration overview","text":"Note
This document describes the Camel integration for Kura 2.1.0
Kura provides two main integration points for Camel:
The first allows one to configure Camel to provide data and receive commands from any CloudService instance which is configured in Kura. For example the default CloudService instance which is backed by MQTT.
The second approach allows one to create a custom CloudService implementation and route data coming from other Kura applications with the routes provided by this Camel context.
"},{"location":"cloud-platform/apache-camel-integration/kura-camel/#deploying-additional-camel-components","title":"Deploying additional Camel components","text":"Kura comes with the following Camel components pre-installed:
camel-core
camel-core-osgi
camel-stream
If additional Camel components are required, they can be installed using deployment packages (DP), as common with Kura.
There are pre-packaged DPs available for e.g. AMQP, OPC UA, MQTT and other Camel components outside of the Kura project.
"},{"location":"connect-field-devices/IO-apis/","title":"I/O APIs","text":"The full Eclipse Kura API reference is available here.
In this page, the developer can find a synthetic grouping of the I/O APIs added starting from Kura 3.1.0.
Drivers
Assets
An Asset is a logical representation of a field device, described by a list of Channels. The Asset uses a specific Driver instance to communicate with the underlying device and it models a generic device resource as a Channel. A register in a PLC or a GATT Characteristic in a Bluetooth device are examples of Channels. In this way, each Asset has multiple Channels for reading and writing data from/to an Industrial Device.
Assets can be used as Wire Components to access the resources referenced by the defined channels inside a Wire Graph, see the Assets as Wire Components guide for more details.
"},{"location":"connect-field-devices/asset-implemetation/#channel-example","title":"Channel Example","text":"To further describe the concept of Channel and Asset, the following table shows a set of PLC register addresses as provided in a typical PLC documentation.
Name Entity Address LED1 COILS 2049 LED2 COILS 2050 LED3 COILS 2051 LED4 RED COILS 2052 LED4 GREEN COILS 2053 LED4 BLUE COILS 2054 Counter 3 INPUT REGISTERS 515 Quad Counter INPUT REGISTERS 520 Toggle 4 DISCRETE INPUTS 2052 Toggle 5 DISCRETE INPUTS 2053 Toggle 6 DISCRETE INPUTS 2054 Reset Counter 3 COILS 3075 Reset Quad Counter COILS 3084The corresponding Channels definition in the Asset is as follows:
As shown in the previous image, the Channel definition in an Asset results easily mappable to what available in a generic PLC documentation.
Once defined the Channels in an Asset, a simple Java application that leverages the Asset API can easily communicate with the Field device by simply referring to the specific Channel of interest.
"},{"location":"connect-field-devices/asset-implemetation/#channel-definition","title":"Channel Definition","text":"For the READ and READ/WRITE channels, the Asset typically asks the driver to provide a value based on the value.type. If the scaleoffset.type is LONG or DOUBLE, the type requested will be one of these and the final value (after the scale and offset operation) will be transformed into the data type expected by value.type.
"},{"location":"connect-field-devices/asset-implemetation/#arithmetic-with-scale-and-offset","title":"Arithmetic with scale and offset","text":"The Asset supports applying a scale and offset to the values obtained by the attached Driver during read operations and to the values received in listen mode.
Warning
Application of scale and offset for write operations is not supported.
The following modes are implemented for computing scale and offset:
DOUBLE
INTEGER
LONG
FLOAT
The values of the scale and offset configuration parameters and the value obtained from the Driver are all converted to the mode type using the Java casting and then the following operation is performed: channel_value * scale + offset
. The operation result is casted again to value.type to produce the final channel value.
The values of the scale and offset parameters are parsed from channel configuration as doubles.
The mode can be selected in the following way:
DOUBLE
or LONG
the corrisponding mode will be used. The largest representable LONG
is 2^53DEFINED_BY_VALUE_TYPE
the operation mode is determinated by value.type.Example of DOUBLE
mode: channel configured with:
DOUBLE
Since scaleoffset.type is DOUBLE
, the scale and offset mode is forced to DOUBLE
.
If channel_value
is 5 (INTEGER) the result is: (int) ((double) channel_value * (double) 3.25d + (double) 1.5d) = 17
.
Example of INTEGER
mode: channel configured with:
DEFINED_BY_VALUE_TYPE
Since scaleoffset.type is DEFINED_BY_VALUE_TYPE
, the mode determined by the value.type parameter (INTEGER
) will be used.
If channel_value
is 5 (INTEGER) the result is: (int) (channel_value * (int) 3.25d + (int) 1.5d) = 16
.
Example of DOUBLE
mode: channel configured with:
DEFINED_BY_VALUE_TYPE
If channel_value
is 5 (DOUBLE) the result is: (double) (channel_value * (double) 3.25d + (double) 1.5d) = 17.75
.
Warning
If the mode is LONG
or INTEGER
the decimal part of the scale and offset value will be discarded.
As the examples show the final result can be different depending on the used mode and value.type.
"},{"location":"connect-field-devices/asset-implemetation/#driver-specific-parameters","title":"Driver specific parameters","text":"The parameters that are not included in list of driver independent parameters above are driver specific. These parameters are used to identify the resource addressed by the channel.
Driver specific parameters are described in the driver documentation.
"},{"location":"connect-field-devices/asset-implemetation/#other-asset-configurations","title":"Other Asset Configurations","text":"The creation of the channels is a process that could be very time and effort consuming. For this reason, once the user has created the desired channels, it is possible to download the entire list from the web UI, by clicking the Download Channels
button:
The list is downloaded in csv format and is represented in the form of a table, whose columns represent the entries for the options in the channel definition, while each row is equivalent to a specific channel. For example, the resulting csv file retrieved from downloading the list of channels in the image above is:
The resulting table is composed by some static, pre-defined options (the ones mentioned in Channel Definition section above, from enabled
to listen
) that are the same for each component and the ones introduced by the specific bundle under analisys. In this case, the modbus driver introduces these driver-specific options:
The download tool is extremely useful in all those situations where the user wants to quickly load a long list of channels at once: for example, it can easily clone the same list in multiple assets, export it to another device, or simply save it locally to always have a copy of the channels ready.
"},{"location":"connect-field-devices/asset-implemetation/#csv-upload","title":"CSV upload","text":"The Upload Channels
button allows the user to load a local csv file to create the channel list in one shot: the uploading file must implement the same table-structure described in the \"Channels download\" section above, so with each rows representing a channels, and each column one entry of the channel's options.
Once the user clicks on the button, will be shown a pop-up in which there are a button to locate the file in the user's filesystem and two checkboxes to allow the uploading phase customization. After clicking on Upload
, if the process is succesful, the new channels list will be shown, and the user is just asked to click on the Apply
button to save the asset variation.
The Force import empty string policy
checkbox forces the parsing of all empty values present in the csv as empty strings, for all those channel's options that are typed to String and \"not required\" by the metatype.
So, this box must be checked when the user wants that all empty values from the csv are considered as empty strings (\"\"
) when parsed to driver-specific channel option, defined by the metatype as String type and not required. So, those values that are null
in the csv, will be set as \"\"
in the channel options. The user must be cautious, because the framework supposes that it's consciously leaving empty values in the csv.
Otherwise, if the box is unchecked, all the csv empty values will be considered as null
strings and parsed to the default value set in the metatype of the driver.
If, for example, the user downloads the channels list following the steps described in the precious section, it could upload the same csv file into an other asset, or another device, to get the exactly same asset configuration.
"},{"location":"connect-field-devices/asset-implemetation/#replace-current-channels","title":"Replace current channels","text":"The Replace current channels
must be checked when the user wants to replace all the channels currently present in the asset, with the ones that will be created by the csv uploading.
The ASSET-V1 namespace allows to perform remote operations on the assets defined in an Kura-powered device. The requests and responses are represented as JSON arrays placed in the body of the MQTT payload.
The namespace includes the following topics.
"},{"location":"connect-field-devices/asset-v1-mqtt-namespace/#getassets","title":"GET/assets","text":"This topic is used to retrieve metadata describing the assets defined on a specific device and their channel configuration.
"},{"location":"connect-field-devices/asset-v1-mqtt-namespace/#request-format","title":"Request format","text":"The request can contain JSON array containing a list of asset names for which the metadata needs to be returned. The request JSON must have the following structure:
[\n {\n \"name\": \"asset1\"\n },\n {\n \"name\": \"otherAsset\"\n }\n]\n
The request JSON is an array with all elements of the type object
. The array object has the following properties:
If the provided array is empty or the request payload is empty, the metadata describing all assets present on the device will be returned.
"},{"location":"connect-field-devices/asset-v1-mqtt-namespace/#response-format","title":"Response format","text":"The response payload contains a JSON array with the following structure:
[\n {\n \"name\": \"asset1\",\n \"channels\": [\n {\n \"name\": \"first_channel\",\n \"type\": \"INTEGER\",\n \"mode\": \"READ\"\n },\n {\n \"name\": \"second_channel\",\n \"type\": \"BOOLEAN\",\n \"mode\": \"READ_WRITE\"\n },\n {\n \"name\": \"other_channel\",\n \"type\": \"STRING\",\n \"mode\": \"WRITE\"\n }\n ]\n },\n {\n \"name\": \"otherAsset\",\n \"channels\": []\n },\n {\n \"name\": \"nonExistingAsset\",\n \"error\": \"Asset not found\"\n }\n]\n
All elements of the array are of the type object
. The array object has the following properties:
error
property are mutually exclusive. This object is an array with all elements of the type object
and they have the following properties:READ
, WRITE
or READ_WRITE
.BOOLEAN
, BYTE_ARRAY
, DOUBLE
, INTEGER
, LONG
, FLOAT
, STRING
.This topic is used to perform a read operation on a specified set of assets and channels.
"},{"location":"connect-field-devices/asset-v1-mqtt-namespace/#request-format_1","title":"Request format","text":"The request can contain a JSON array with the following structure:
[\n {\n \"name\": \"asset1\",\n \"channels\": [\n {\n \"name\": \"channel1\"\n },\n {\n \"name\": \"channel2\"\n },\n {\n \"name\": \"otherChannel\"\n }\n ]\n },\n {\n \"name\": \"otherAsset\"\n }\n]\n
The request JSON is an array with all elements of the type object
. If the list is empty or if the request payload is empty all channels of all assets will be read. The array object has the following properties:
object
. The array object has the following properties:The response is returned as a JSON array placed in the body of the response:
[\n {\n \"name\": \"asset1\",\n \"channels\": [\n {\n \"name\": \"first_channel\",\n \"type\": \"INTEGER\",\n \"value\": \"432\",\n \"timestamp\": 1234550\n },\n {\n \"name\": \"second_channel\",\n \"type\": \"BOOLEAN\",\n \"value\": \"true\",\n \"timestamp\": 1234550\n },\n {\n \"name\": \"other_channel\",\n \"error\": \"Read failed\",\n \"timestamp\": 1234550\n },\n {\n \"name\": \"binary_channel\",\n \"type\": \"BYTE_ARRAY\",\n \"value\": \"dGVzdCBzdHJpbmcK\",\n \"timestamp\": 1234550\n }\n ]\n },\n {\n \"name\": \"nonExistingAsset\",\n \"error\": \"Asset not found\"\n }\n]\n
The response JSON is an array with all elements of the type object
. The array object has the following properties:
object
. The array object has the following properties:BOOLEAN
, BYTE_ARRAY
, DOUBLE
, INTEGER
, LONG
, FLOAT
, STRING
.BYTE_ARRAY
, the result will be represented using the base64 encoding.Performs a write operation on a specified set of channels and assets.
"},{"location":"connect-field-devices/asset-v1-mqtt-namespace/#request-format_2","title":"Request format","text":"The request must contain a JSON array with the following structure:
[\n {\n \"name\": \"asset1\",\n \"channels\": [\n {\n \"name\": \"first_channel\",\n \"type\": \"INTEGER\",\n \"value\": \"432\",\n },\n {\n \"name\": \"second_channel\",\n \"type\": \"BOOLEAN\",\n \"value\": \"true\",\n },\n {\n \"name\": \"binary_channel\",\n \"type\": \"BYTE_ARRAY\",\n \"value\": \"dGVzdCBzdHJpbmcK\",\n }\n ]\n }\n]\n
The array object has the following properties:
object
. The array object has the following properties:BOOLEAN
, BYTE_ARRAY
, DOUBLE
, INTEGER
, LONG
, FLOAT
, STRING
.The response uses the same format as the EXEC/read
request, in case of success the type and value properties in the response will report the same values specified in the request.
Eclipse Kura introduces a model based on the concepts of Drivers and Assets to simplify the communication with the field devices attached to a gateway.
A Driver encapsulates the communication protocol and its configuration parameters, dealing with the low-level characteristics of the field protocol. It opens, closes and performs the communication with the end field device. It also exposes field protocol specific information that can be used by upper levels of abstraction to simplify the interaction with the end devices.
An Asset is a logical representation of a field device, described by a list of Channels. The Asset uses a specific Driver instance to communicate with the underlying device and it models a generic device resource as a Channel. A register in a PLC or a GATT Characteristic in a Bluetooth device are examples of Channels. In this way, each Asset has multiple Channels for reading and writing data from/to an Industrial Device.
"},{"location":"connect-field-devices/driver-and-assets/#channel-example","title":"Channel Example","text":"To further describe the concept of Channel and Asset, the following table shows a set of PLC register addresses as provided in a typical PLC documentation.
Name Entity Address LED1 COILS 2049 LED2 COILS 2050 LED3 COILS 2051 LED4 RED COILS 2052 LED4 GREEN COILS 2053 LED4 BLUE COILS 2054 Counter 3 INPUT REGISTERS 515 Quad Counter INPUT REGISTERS 520 Toggle 4 DISCRETE INPUTS 2052 Toggle 5 DISCRETE INPUTS 2053 Toggle 6 DISCRETE INPUTS 2054 Reset Counter 3 COILS 3075 Reset Quad Counter COILS 3084The corresponding Channels definition in the Asset is as follows:
As shown in the previous image, the Channel definition in an Asset results easily mappable to what available in a generic PLC documentation.
Once defined the Channels in an Asset, a simple Java application that leverages the Asset API can easily communicate with the Field device by simply referring to the specific Channel of interest.
"},{"location":"connect-field-devices/driver-and-assets/#drivers-and-assets-in-kura-administrative-ui","title":"Drivers and Assets in Kura Administrative UI","text":"Kura provides a specific section of the UI to allow users to manage the different instances of Drivers and Assets. Using the Kura Web UI the user can instantiate and manage Drivers
but also can manage Assets instances based on existing drivers.
The user interface allows also to perform specific reads on the configured Assets' channels clicking on the Data tab for the selected Asset.
"},{"location":"connect-field-devices/driver-implemetation/","title":"Driver implementation","text":"A Driver encapsulates the communication protocol and its configuration parameters.
The Driver API abstracts the specificities of the end Fieldbus protocols providing a clean and easy to use set of calls that can be used to develop end-applications.
Using the Driver APIs, an application can simply use the connect and disconnect methods to open or close the connection with the Field device. Furthermore, the read and write methods allow exchanging data with the Field device.
A Driver instance can be associated with an Asset to abstract even more the low-level specificities and allow an easy and portable development of the Java applications that need to interact with sensors, actuators, and PLCs.
The Asset will use the Driver's protocol-specific channel descriptor to compose the Asset Channel description.
"},{"location":"connect-field-devices/driver-implemetation/#driver-configuration","title":"Driver Configuration","text":"Generally, a Driver instance is a configurable component which parameters can be updated in the Drivers and Assets section of the Kura Administrative User Interface.
"},{"location":"connect-field-devices/driver-implemetation/#supported-field-protocols-and-availability","title":"Supported Field Protocols and Availability","text":"Drivers will be provided as add-ons available in the Eclipse IoT Marketplace. Please see here for a complete list.
"},{"location":"connect-field-devices/driver-implemetation/#driver-specific-optimizations","title":"Driver-Specific Optimizations","text":"The Driver API provides a simple method to read a list of Channel Records:
public void read(List<ChannelRecord> records) throws ConnectionException;\n
Typically, since the records to read do not change until the Asset configuration is changed by the user, a Driver can perform some optimisations to efficiently read the requested records at once. For example, a Modbus driver can read a range of holding registers using a single request.
Since these operations are costly, the Kura API adds methods to ask the driver to prepare reading a given list of records and execute the prepared read:
public PreparedRead prepareRead(List<ChannelRecord> records);\n
Invocation of the preparedRead method will result in a PreparedRead instance returned.
On a PreparedRead, the execute method will perform the optimized read request.
"},{"location":"connect-field-devices/eddystone-driver/","title":"Eddystone\u2122 Driver","text":"Eclipse Kura offers support for Eddystone\u2122 protocol via a specific driver. The driver is available only for gateways that support the new Bluetooth LE APIs. It can be used into the Wires framework, the Asset model or directly using the Driver itself.
"},{"location":"connect-field-devices/eddystone-driver/#features","title":"Features","text":"The Eddystone\u2122 driver is designed to listen for incoming beacon packets and to recognise the specific protocol. Of course it's not possible to write data to the beacons, since this is outside the protocol specification. The frame format to be filtered can be chosen from the channel definition. For more information about Eddystone\u2122 frame format, see here.
"},{"location":"connect-field-devices/eddystone-driver/#installation","title":"Installation","text":"As the others Drivers supported by Eclipse Kura, it is distributed as a deployment package on the Eclipse Marketplace here. It can be installed following the instructions provided here.
"},{"location":"connect-field-devices/eddystone-driver/#instance-creation","title":"Instance creation","text":"A new Eddystone Driver instance can be created either by clicking the New Driver button in the dedicated Drivers and Assets Web UI section or by clicking on the +
button under Services. In both cases, the org.eclipse.kura.driver.eddsytone
factory must be selected and a unique name must be provided for the new instance. Once instantiated, the Driver has to be configured setting the Bluetooth interface name (i.e. hci0
) that will be used to connect to the device.
The Eddystone Driver channel can be configured with the following parameters:
READ
, WRITE
, or READ_WRITE
).UID
and URL
typed are supported.Eclipse Kura provides support for field protocol implementations as add-ons deployable directly from the Eclipse Marketplace for IoT site. Moreover, several devices are supported using the Kura Driver model.
Currently, the following field protocols and devices are supported and downloadable from the Eclipse Marketplace in form of Kura Drivers:
Protocol/Device Kura 3.x Kura 4.x Kura 5.x OPC-UA link link link S7 link link link iBeacon N.A. link link Eddystone N.A. link link TiSensorTag link link link GPIO link link link SenseHat link link link"},{"location":"connect-field-devices/gpio-driver/","title":"GPIO Driver","text":"The GPIO Driver manages the General Purpose IOs on a gateway using the Driver model. Based on the GPIO Service, the driver can be used in the Wires framework, the Asset model or directly using the Driver itself.
"},{"location":"connect-field-devices/gpio-driver/#features","title":"Features","text":"The GPIO Driver includes the following features:
As the other Drivers supported by Eclipse Kura, it is distributed as a deployment package on the Eclipse Marketplace for Kura 3.x and 4.x/5.x. It can be installed following the instructions provided here.
"},{"location":"connect-field-devices/gpio-driver/#instance-creation","title":"Instance creation","text":"A new GPIO Driver instance can be created either by clicking the New Driver button in the dedicated Drivers and Assets Web UI section or by clicking on the + button under Services. In both cases, the org.eclipse.kura.driver.gpio
factory must be selected and a unique name must be provided for the new instance. Once instantiated, the GPIO Driver is ready to use and no configuration is needed.
The GPIO Driver channel can be configured with the following parameters:
READ
, WRITE
, or READ_WRITE
).#select resource
selection has no effect on the channel.INPUT
and OUTPUT
. The #select direction
selection has no effect on the channel.resource.trigger: the type of event that triggers the listener, if selected. Possible values are:
NONE
: no event will trigger the listener.
RISING_EDGE
, FALLING_EDGE
, BOTH_EDGES
: the listeners will be triggered respectively by a low-high transition, a high-low transition or both.HIGH_LEVEL
,LOW_LEVEL
, BOTH_LEVELS
: the listeners will be triggered respectively by the detection of a high, low or both levels. Please note that these options aren't supported by all the devices.In this section a simple example on the GPIO Driver using a RaspberryPi will be presented. Before configuring the Driver, arrange a setup as shown in the following picture, using a breadboard, a led, a 120-ohm resistor and some wires. Connect the yellow wire to a ground pin on the RasperryPi connector (i.e. pin 6) and the red one to pin 40 (a.k.a. gpio21).
From the Drivers and Assets tab, create a new GPIO Driver, call it GPIODriver and add an Asset as shown in the following picture.
The asset is configured to manage a gpio, called LED, as an output and drives it writing a boolean value. The LED channel is attached to the gpio21 on the RaspberryPi. In the Data tab, fill the Value form with true and press Apply: the green led will switch on. Writing a false will switch off the led.
"},{"location":"connect-field-devices/ibeacon-driver/","title":"iBeacon\u2122 Driver","text":"Eclipse Kura provides a driver specifically developed to manage iBeacon\u2122 protocol. The driver is available only for gateways that support the new Bluetooth LE APIs. They can be used into the Wires framework, the Asset model or directly using the Driver itself.
"},{"location":"connect-field-devices/ibeacon-driver/#features","title":"Features","text":"The iBeacon\u2122 driver is designed to listen for incoming beacon packets and to recognise the specific protocol. Of course it's not possible to write data to the beacons, since this is outside the protocol specification.
"},{"location":"connect-field-devices/ibeacon-driver/#installation","title":"Installation","text":"As the others Drivers supported by Eclipse Kura, it is distributed as a deployment package on the Eclipse Marketplace here. It can be installed following the instructions provided here.
"},{"location":"connect-field-devices/ibeacon-driver/#instance-creation","title":"Instance creation","text":"A new iBeacon instance can be created either by clicking the New Driver button in the dedicated Drivers and Assets Web UI section or by clicking on the +
button under Services. In both cases, the org.eclipse.kura.driver.ibeacon
factory must be selected and a unique name must be provided for the new instance. Once instantiated, the Driver has to be configured setting the Bluetooth interface name (i.e. hci0
) that will be used to connect to the device.
The iBeacon Driver channel can be configured with the following parameters:
READ
, WRITE
, or READ_WRITE
).This Driver implements the client side of the OPC UA protocol using the Driver model. The Driver can be used to interact as a client with OPC UA servers using different abstractions, such as the Wires framework, the Asset model or by directly using the Driver itself.
The Driver is distributed as a deployment package on Eclipse Marketplace for Kura 3.x and 4.x/5.x. It can be installed following the instructions provided here.
"},{"location":"connect-field-devices/opcua-driver/#features","title":"Features","text":"The OPC UA Driver features include:
A new OPC UA instance can be created either by clicking the New Driver button in the dedicated Drivers and Assets Web UI section or by clicking on the + button under Services. In both cases, the org.eclipse.kura.driver.opcua
factory must be selected and a unique name must be provided for the new instance.
The OPC UA Driver channel configuration is composed of the following parameters:
READ
, WRITE
, or READ_WRITE
).opcua.type: The OPC-UA built-in type of the attribute to be read/written. If set to DEFINED_BY_JAVA_TYPE (default), the driver will attempt to determine the OPC-UA type basing on the value type parameter value. If the read/write operation fails, it may be necessary to use one of the other values of this configuration parameter to explicitly select the type.
This parameter also lists the OPC-UA types currently supported by the driver.
Not all value type and opcua.type combinations are valid, the allowed ones are the following:
opcua.type Allowed value.types Recommended value.type BOOLEAN BOOLEAN BOOLEAN SBYTE INTEGER, LONG, FLOAT, DOUBLE, STRING INTEGER INT16 INTEGER, LONG, FLOAT, DOUBLE, STRING INTEGER INT32 INTEGER, LONG, FLOAT, DOUBLE, STRING INTEGER INT64 INTEGER, LONG, FLOAT, DOUBLE, STRING LONG BYTE INTEGER, LONG, FLOAT, DOUBLE, STRING INTEGER UINT16 INTEGER, LONG, FLOAT, DOUBLE, STRING INTEGER UINT32 INTEGER, LONG, FLOAT, DOUBLE, STRING LONG UINT64 INTEGER, LONG, FLOAT, DOUBLE, STRING STRING FLOAT FLOAT, STRING FLOAT DOUBLE DOUBLE, STRING DOUBLE STRING STRING STRING BYTE_STRING BYTE_ARRAY BYTE_ARRAY BYTE_ARRAY BYTE_ARRAY BYTE_ARRAY SBYTE_ARRAY BYTE_ARRAY BYTE_ARRAYUsing a non allowed value.type will result in read/write operation failures. It should be noted that there is not a one to one match between the opcua.type and Java value.type. It is recommended to compare the allowed ranges for numeric types specified in OPC-UA Reference and Java reference for selecting the best match.
node.id.type: The type of the node id (see the Node Id types section)
If the listen flag is enabled for an OPC-UA channel, the driver will request the server to send notifications if it detects changes in the referenced attribute value.
In order to enable this, the driver will create a global subscription (one per Driver instance), and a monitored item for each channel. See [1] for more details. The Subscription publish interval global configuration parameter can be used to tune the subscription publishing interval.
The listen.subscribe.to.children parameter can be used to enable the Subtree Subscription feature.
[1] MonitoredItem model
"},{"location":"connect-field-devices/opcua-driver/#node-id-types","title":"Node ID types","text":"The Driver supports the following node id types:
Node ID Type Format of node.id NUMERIC node.id must be parseable into an integer STRING node.id can be any string OPAQUE Opaque node ids are represented by raw byte arrays. In this case node.id must be the base64 encoding of the node id. GUID node.id must be a string conforming to the format described in the documentation of the java.util.UUID.toString() method."},{"location":"connect-field-devices/opcua-driver/#certificate-setup","title":"Certificate setup","text":"In order to use settings for Security Policy different than None, the OPCUA driver must be configured to trust the server certificate and a new client certificate - private key pair must be generated for the driver. These items can be placed in a Java keystore that can be referenced from driver configuration. The keystore does not exist by default and without it connections that use Security Policy different than None will fail.
The following steps can be used to generate the keystore:
Copy the following example script to the device using SSH, it can be used to import the server certificate and generate the client key pair. It can be modified if needed:
#!/bin/bash\n\n# the alias for the imported server certificate\nSERVER_ALIAS=\"server-cert\"\n\n# the file name of the generated keystore\nKEYSTORE_FILE_NAME=\"opcua-keystore.ks\"\n# the password of the generated keystore and private keys, it is recommended to change it\nKEYSTORE_PASSWORD=\"changeit\"\n\n# server certificate to be imported is expected as first argument\nSERVER_CERTIFICATE_FILE=\"$1\"\n\n# import existing certificate\nkeytool -import \\\n -alias \"${SERVER_ALIAS}\" \\\n -file \"${SERVER_CERTIFICATE_FILE}\" \\\n -keystore \"${KEYSTORE_FILE_NAME}\" \\\n -noprompt \\\n -storepass \"${KEYSTORE_PASSWORD}\"\n\n# alias for client certificate\nCLIENT_ALIAS=\"client-cert\"\n# client certificate distinguished name, it is recommended to change it \nCLIENT_DN=\"CN=MyCn, OU=MyOu, O=MyOrganization, L=Amaro, S=UD, C=IT\"\n# the application id, must match the corresponding parameter in driver configuration\nAPPLICATION_ID=\"urn:kura:opcua:client\"\n\n# generate the client private key and certificate\nkeytool -genkey \\\n -alias \"${CLIENT_ALIAS}\" \\\n -keyalg RSA \\\n -keysize 4096 \\\n -keystore \"${KEYSTORE_FILE_NAME}\" \\\n -dname \"${CLIENT_DN}\" \\\n -ext ku=digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment \\\n -ext eku=clientAuth \\\n -ext \"san=uri:${APPLICATION_ID}\" \\\n -validity 1000 \\\n -noprompt \\\n -storepass ${KEYSTORE_PASSWORD} \\\n -keypass ${KEYSTORE_PASSWORD}\n
Update the following parameters in driver configuration:
opcua-keystore.ks
file created at step 3.CLIENT_ALIAS
script variable (the default is client-cert
) KEYSTORE_PASSWORD
script variable (the default value is changeit
)Application URI -> Set the value of the APPLICATION_ID
script variable (default value should be already ok).
Configurare the server to trust the client certificate generated at step 3. The steps required to do this vary depending on the server. Usually the following steps are needed:
The driver can be configured to recursively visit the children of a folder node and create a Monitored Item for the value of each discovered variable node with a single channel in Asset configuration.
Warning: This feature should be used with care since it can cause high load on both the gateway and the server if the referenced folder contains a large number of nodes and/or the notification rate is high.
"},{"location":"connect-field-devices/opcua-driver/#channel-configuration_1","title":"Channel configuration","text":"In order to configure the driver to perform the discovery operation, a single channel can be defined with the following configuration:
READ
STRING
(see below)true
true
The rest of the configuration parameters can be specified in the same way as for the single node subscription use case.
The listen.sampling.interval, listen.queue.size and listen.discard.oldest parameters of the root will be used for all subscriptions on the subtree.
"},{"location":"connect-field-devices/opcua-driver/#discovery-procedure","title":"Discovery procedure","text":"The driver will consider as folders to visit all nodes that whose type definition is FolderType
, or more precisely all nodes with the following reference:
HasTypeDefinition
: * namespace index: 0 * node id: 61 (numeric) * URN: http://opcfoundation.org/UA/
The driver will subscribe to all the variable nodes found.
"},{"location":"connect-field-devices/opcua-driver/#event-reporting","title":"Event reporting","text":"If the Driver is used by a Wire Asset, it will emit on the wire a single message per received event.
All emitted events will contain a single property. Depending on the value of the Subtree subscription events channel name format global configuration parameter, the name of this property is the node id or the browsed path of the source OPCUA node relative to the root folder defined in the channel configuration.
"},{"location":"connect-field-devices/opcua-driver/#type-conversion","title":"Type conversion","text":"The current version of the driver tries to convert the values received for all the events on a subtree to the type defined in the value.type configuration parameter.
Since the value types of the discovered nodes are heterogeneous, the conversion might fail if the types are not compatible (e.g. if value.type is set to INTEGER
and the received value is a string).
Setting value.type to STRING
should allow to perform safe conversions for most data types.
This Driver implements the s7comm protocol and can be used to interact with Siemens S7 PLCs using different abstractions, such as the Wires framework, the Asset model or by directly using the Driver itself.
The Driver is distributed as a deployment package on the Eclipse Marketplace for Kura 3.x and 4.x/5.x. It can be installed following the instructions provided here.
"},{"location":"connect-field-devices/s7-driver/#features","title":"Features","text":"The S7comm Plc Driver features include:
A new S7comm driver instance can be created either by clicking the New Driver button in the dedicated Drivers and Assets Web UI section or by clicking on the + button under Services. In both cases, the org.eclipse.kura.driver.s7plc
factory must be selected and a unique name must be provided for the new instance.
The S7 Driver channel configuration is composed of the following parameters:
READ
, WRITE
, or READ_WRITE
).STRING
or BYTE_ARRAY
. In the other cases, this parameter is ignored and the data size is automatically derived from the s7.data.type.BOOLEAN
and s7.data.type is set to BOOL
. In the other cases, this parameter is ignored.When performing operations that deal with numeric data, two data types are involved:
The Java primitive type that is used in the ChannelRecords exchanged between the driver and Java applications. (the Java type of the value received/supplied by external applications from/to the Driver in case of a read/write operation). This value type is specified by the value type configuration property.
The S7 type of the data on the PLC. This value type is specified by the s7.data.type configuration property. The following S7 data types are supported:
S7 Data Type Size SignINT
16 bits signed
DINT
32 bits signed
WORD
16 bits unsigned
DWORD
32 bits unsigned
REAL
32 bits signed
BOOL
1 bit n.d. BYTE
1 byte unsigned
CHAR
1 byte (only supported as char arrays using the String Java data type) n.d. The Driver automatically adapts the data type used by external applications and the S7 device depending on the value of the two configuration properties mentioned above.
The adaptation process involves the following steps:
Each device data type is internally converted by the driver from/to a Java type large enough to represent the value of the device data without losing precision. The type mappings are the following:
S7 Data Type Java TypeINT
int
DINT
int
WORD
int
DWORD
long
REAL
float
BOOL
boolean
BYTE
int
If the value type of the channel does not match the Java type specified in mapping above, a conversion is performed by the Driver to convert it to/from the matching type, choosing appropriately between the Number.toInt()
, Number.toLong()
, Number.toFloat()
or Number.toDouble()
methods. Precision losses may occur if the Java type used by the external application is not suitable to represent all possible values of the device data type.
The driver supports transferring data as raw byte arrays or ASCII strings:
BYTE_ARRAY
, the data.type configuration property must be set to BYTE
and the byte.count property must be set to the data length in bytes.STRING
, the data.type configuration property must be set to CHAR
and the array.data.length property must be set to the data length in bytes.The Driver supports setting the value of single bits without overwriting the other bits of the same byte. This operation can be performed defining a channel having BOOLEAN
as value type, BOOL
as s7.data.type and the proper index set to the bit.index property.
The Driver will fetch the byte containing the bit to be written, update its contents and then write back the obtained value. If multiple bits on the same byte need to be modified, the driver will perform only one read and write for that byte. If bits that need to be changed are located in contiguous bytes, the driver will perform only one bulk read and one bulk write transferring all the required data in a single request.
"},{"location":"connect-field-devices/sensehat-driver/","title":"RaspberryPi SenseHat driver","text":"The SenseHat driver allows to interact to a RaspberryPi SenseHat device using Kura Driver, Asset and Wires frameworks. The driver allows access to the following resources:
The driver-specific channel configuration contains a single parameter, resource, which allows to select the specific device resource that the channel is addressing (a sensor, a joystick event, etc).
Note about running on OpenJDK
If some exceptions reporting Locked by other application
are visible in the log and the driver fails to start, try switching to the Oracle JVM by installing the oracle-java8-jdk
package. For more information on the problem, please see this GitHub issue.
As the others Drivers supported by Kura, it is distributed as a deployment package on the Eclipse Marketplace here. It can be installed following the instructions provided here.
In order to use the driver, the Sensehat Support Library Bundle for Eclipse Kura needs to be installed as a prerequisite dependency. It is available from Eclipse Marketplace here.
"},{"location":"connect-field-devices/sensehat-driver/#sensors","title":"Sensors","text":"The following values of the resource parameters refer to device sensors:
Resource Unit Description ACCELERATION_X, ACCELERATION_Y, ACCELERATION_Z G The proper acceleration for each axis GYROSCOPE_X, GYROSCOPE_Y, GYROSCOPE_Z rad/S The angular acceleration for each axis MAGNETOMETER_X, MAGNETOMETER_Y, MAGNETOMETERE_Z uT The magnetometer value for each axis HUMIDITY %rH The relative humidity PRESSURE mbar The pressure value TEMPERATURE_FROM_HUMIDITY \u00b0C The temperature obtained from the humidity sensor TEMPERATURE_FROM_PRESSURE \u00b0C The temperature obtained from the pressure sensorThe channels referencing sensor resources can only be used for reads and only in polling mode. The driver will attempt to convert the value obtained from the sensor into the data type selected using the value.type parameter
Example sensors Asset configuration:
"},{"location":"connect-field-devices/sensehat-driver/#joystick","title":"Joystick","text":"The SenseHat joystick provides four buttons:
For each button, the driver allows to listen to the following events:
The values of the resource parameter related to joystick have the following structure:
JOYSTICK_{BUTTON}_{EVENT}
Channels referencing joystick events must use LONG as value.type. The channel value supplied by the driver is the Java timestamp in milliseconds of the Joystick event, a value of 0 signifies that no events have been observed yet.
Joystick related channels can be only used for reading and both in polling and event-driven mode.
Example joystick Asset configuration:
"},{"location":"connect-field-devices/sensehat-driver/#led-matrix","title":"LED Matrix","text":"The driver allows accessing the SenseHat LED matrix in two ways:
The coordinate system used by the driver defines the x
coordinate as increasing along the direction identified by the joystick RIGHT button and the y
coordinate increasing along the direction identified by the DOWN joystick button.
In monochrome mode, only two colors will be used: the front color and the back color.
"},{"location":"connect-field-devices/sensehat-driver/#front-and-back-colors","title":"Front and back colors","text":"Front and back colors can be configured using channels having the following values for the resource parameter:
These channel types allow to set the rgb components of the front and back color and can only be used in write mode. The supplied value must be a floating point number between 0 (led turned off) and 1 (full brightness). Note: Front and back colors are internally represented using the RGB565 format. The available colors are only the ones that can be represented using RGB565 and are supported by the device. Front and back color are retained for successive draw operations, the initial value for both colors is black (led turned off).
"},{"location":"connect-field-devices/sensehat-driver/#drawing","title":"Drawing","text":"The following resources can be used for modifying framebuffer contents:
LED_MATRIX_FB_MONOCHROME:
A channel of this type allows to set the framebuffer contents in monochrome mode. It can only be used in write mode and its value.type must be BYTE_ARRAY.
The supplied value must be a byte array of length 64 that represent the state of the 8x8 led matrix. The offset in the array of a pixel having coordinates (x, y)
is y*8 + x
. The back/front color will be used for a pixel if the corresponding byte in the array is zero/non-zero.
LED_MATRIX_CHARS:
A channel of this type allows showing a text message using the LED matrix. It can only be used for writing and its value.type must be STRING. The characters of the message will be rendered using the front color and the background using the back color.
The following resource allows writing the framebuffer using the RGB565 format:
LED_MATRIX_FB_RGB565:
A channel of this type allows to set the framebuffer contents in RGB565 mode. It can only be used in write mode and its value.type must be BYTE_ARRAY.
The supplied value must be a byte array of length 128 that represents the state of the 8x8 led matrix. Each pixel is represented by two consecutive bytes in the following way:
| MSB | LSB |\n| RRRRRGGG | GGGBBBBB |\n| 15 ... 8 | 7 ... 0 |\n
The LSB must be stored first in the array, the offset of the LSB and MSB for a pixel at coordinates (x, y)
is the following:
2*(y*8 + x)
2*(y*8 + x) + 1
LED_MATRIX_CLEAR:
Writing anything to a LED_MATRIX_CLEAR channel will clear the framebuffer turning off all leds.
LED_MATRIX_ROTATION:
Allows to rotate the framebuffer of 0, 90, 180, and 170 degrees clockwise. Rotation setting will be retained for successive draw operations. The default value is 0. Writes to a LED_MATRIX_ROTATION channel can be performed using any numeric type as value.type.
Example framebuffer Asset configuration:
"},{"location":"connect-field-devices/sensehat-driver/#examples","title":"Examples","text":"This section contains some examples describing how to use the driver using Kura Wires and the Wires Script filter.
"},{"location":"connect-field-devices/sensehat-driver/#moving-a-pixel-using-the-joystick","title":"Moving a pixel using the Joystick","text":"var FB_SIZE = 8\n\nif (typeof(state) === 'undefined') {\n // framebuffer as byte array (0 -> back color, non zero -> front color)\n var fb = newByteArray(FB_SIZE*FB_SIZE|0)\n // record to be emitted for updating the fb\n var outRecord = newWireRecord()\n // property in emitted record containing fb data\n // change the name if needed\n // should match the name of a channel configured as LED_MATRIX_FB_MONOCHROME\n outRecord['fb_mono'] = newByteArrayValue(fb)\n\n state = {\n fb: fb,\n outRecord: outRecord,\n x: 0, // current pixel position\n y: 0,\n dx: 0, // deltas to be added to pixel position\n dy: 0,\n }\n}\n\nif (typeof(actions) === 'undefined') {\n // associations between input property names\n // and position update actions,\n // input can be supplied using an Asset\n // with joystick event channels\n actions = {\n 'up_release' : function () {\n // decrease y coordinate\n state.dy = -1\n },\n 'down_release' : function () {\n // increase y coordinate\n state.dy = 1\n },\n 'left_release' : function () {\n // decrease x coordinate\n state.dx = -1\n },\n 'right_release' : function () {\n // increase x coordinate\n state.dx = 1\n }\n }\n}\n\nif (input.records.length) {\n var input = input.records[0]\n var update = false\n\n for (var prop in input) {\n var action = actions[prop]\n // if there is an action associated with the received property, execute it\n if (action) {\n action()\n // request framebuffer update\n update = true\n }\n }\n\n if (update) {\n // framebuffer update requested\n // clear old pixel\n state.fb[state.y*FB_SIZE + state.x] = 0\n // compute new pixel position\n state.x = (state.x + state.dx + FB_SIZE) % FB_SIZE\n state.y = (state.y + state.dy + FB_SIZE) % FB_SIZE\n // set new pixel\n state.fb[state.y*FB_SIZE + state.x] = 1\n // clear deltas\n state.dx=0\n state.dy=0\n // emit record\n output.add(state.outRecord)\n }\n}\n
"},{"location":"connect-field-devices/sensehat-driver/#using-rgb565-framebuffer","title":"Using RGB565 framebuffer","text":"var FB_SIZE = 8\nvar BYTES_PER_PIXEL = 2\n\nif (typeof(state) === 'undefined') {\n // framebuffer as RGB565 byte array\n var fb = newByteArray(FB_SIZE * FB_SIZE * BYTES_PER_PIXEL | 0)\n // record to be emitted for updating the fb\n var outRecord = newWireRecord()\n // property in emitted record containing fb data\n // change the name if needed\n // must match the name of a channel configured as LED_MATRIX_FB_565\n outRecord['fb_rgb565'] = newByteArrayValue(fb)\n\n // framebuffer array and output record\n state = {\n fb: fb,\n outRecord: outRecord,\n }\n\n RMASK = ((1 << 5) - 1)\n GMASK = ((1 << 6) - 1)\n BMASK = RMASK\n\n // converts the r, g, b values provided as a floating point\n // number between 0 and 1 to RGB565 and stores the result\n // inside the output array\n function putPixel(off, r, g, b) {\n var _r = Math.floor(r * RMASK) & 0xff\n var _g = Math.floor(g * GMASK) & 0xff\n var _b = Math.floor(b * BMASK) & 0xff\n\n var b0 = (_r << 3 | _g >> 3)\n var b1 = (_g << 5 | _b)\n\n state.fb[off + 1] = b0\n state.fb[off] = b1\n }\n\n // parameters for 3 sin waves, one per color component\n RED_WAVE_PARAMS = {\n a: 5,\n b: 10,\n c: 10,\n d: 0\n }\n\n GREEN_WAVE_PARAMS = {\n a: 5,\n b: 10,\n c: 10,\n d: 1\n }\n\n BLUE_WAVE_PARAMS = {\n a: 5,\n b: 10,\n c: 10,\n d: 2\n }\n\n function wave(x, y, t, params) {\n return Math.abs(Math.sin(2*Math.PI*(t + x/params.b + y/params.c + params.d)/params.a))\n }\n}\n\nvar t = new Date().getTime() / 1000\n\nvar off = 0\nfor (var y = 0; y < FB_SIZE; y++)\n for (var x = 0; x < FB_SIZE; x++) {\n var r = wave(x, y, t, RED_WAVE_PARAMS)\n var g = wave(x, y, t, GREEN_WAVE_PARAMS)\n var b = wave(x, y, t, BLUE_WAVE_PARAMS)\n putPixel(off, r, g, b)\n off += 2\n }\n\noutput.add(state.outRecord)\n
"},{"location":"connect-field-devices/sensortag-driver/","title":"TI SensorTag Driver","text":"Eclipse Kura provides a specific driver that can be used to interact with Texas Instruments SensorTag devices. The driver is available only for gateways that support the new Bluetooth LE APIs. It can be used in the Wires framework, the Asset model or directly using the Driver itself.
Warning
The SensorTag driver can be used only with TI SensorTags with firmware version >1.20. If your device has an older firmware, please update it.
"},{"location":"connect-field-devices/sensortag-driver/#features","title":"Features","text":"The SensorTag Driver can be used to get the values from all the sensor installed on the tag (both in polling mode and notification):
Moreover, the following resources can be written by the driver: - read and green leds - buzzer
When a notification is enabled for a specific channel (sensor), the notification period can be set.
"},{"location":"connect-field-devices/sensortag-driver/#installation","title":"Installation","text":"As the other Drivers supported by Kura, it is distributed as a deployment package on the Eclipse Marketplace here and here. It can be installed following the instructions provided here.
"},{"location":"connect-field-devices/sensortag-driver/#instance-creation","title":"Instance creation","text":"A new TiSensorTag Driver instance can be created either by clicking the New Driver button in the dedicated Drivers and Assets Web UI section or by clicking on the + button under Services. In both cases, the org.eclipse.kura.driver.ble.sensortag
factory must be selected and a unique name must be provided for the new instance. Once instantiated, the SensorTag Driver has to be configured setting the Bluetooth interface name (i.e. hci0) that will be used to connect to the device.
The SensorTag Driver channel can be configured with the following parameters:
READ
, WRITE
, or READ_WRITE
).Eclipse Kura provides a specific driver that can be used to interact with Bosch Xdk110 devices. The driver is available only for gateways that support the new Bluetooth LE APIs. It can be used in to the Wires framework, the Asset model or directly using the Driver itself.
Info
The Xdk driver can only be used with Xdk110 with VirtualXdkDemo installed and with firmware version > 3.5.0. If your device has an older firmware, please update it.
"},{"location":"connect-field-devices/xdk-driver/#features","title":"Features","text":"The Xdk Driver can be used to get the values from all the sensor provider by the xdk110 (both in polling mode and notification):
G
The proper acceleration for each axis* GYROSCOPE_X, GYROSCOPE_Y, GYROSCOPE_Z rad/S
The angular acceleration for each axis* LIGHT lux
The light value NOISE DpSpl
The acustic pressure value PRESSURE Pa
The pressure value TEMPERATURE C
The temperature value HUMIDITY %rH
The relative humidity SD_CARD_DETECTION_STATUS boolean
SD-Card detect status PUSH_BUTTONS bit
Button status, encoded as bit field: Bit 0, Button 1; Bit 1, Button 2 MAGNETOMETER_X, MAGNETOMETER_Y, MAGNETOMETERE_Z uT
The magnetometer value for each axis MAGNETOMETER_RESISTENCE ohm
The magnetometer resistence value LED_STATUS bit
Led status, encoded as a bit field: Bit 0: yellow Led; Bit 1: orange Led; Bit 2: red Led VOLTAGE_LEM mV
RMS voltage of LEM sensor *If the Quaternion rappresentation is selected, then:
Resource Unit Description QUATERNION_M, QUATERNION_X, QUATERNION_Y, QUATERNION_Znumber
The rotation-quaternion for each axis When a notification is enabled for a specific channel (sensor), the notification period can't be set. Use the Timer in Wire Graph to set polling.
"},{"location":"connect-field-devices/xdk-driver/#documentation","title":"Documentation","text":"All the information regarding the Xdk110 is available in the Xdk Bosch Connectivity here website. The XDK-Workbench is the tool that can be used to develop software for the Xdk110. It can be downloaded from here. XDK-Workbench is required to install VirtualXdkDemo.
Warning
We found connection problems with Xdk, probably due to issues with XDK-Workbench version 3.6.0. We recommend installing version 3.5.0.
The Virtual XDK application user guide contains all the information regarding the XDK110 UUIDs and data formats here.
Info
To switch between quaternion and sensor representation, the XDK110 needs to be instructed using the 55b741d5-7ada-11e4-82f8-0800200c9a66
UUID. Set it to 0x01
to enable Quaternions.
If quaternion representation is enabled, the data format is as follows:
Bytes Data Type 0,1,2 & 3 Rotation Quaternion M float 4,5,6 & 7 Rotation Quaternion X float 8,9,10 & 11 Rotation Quaternion Y float 12,13,14 & 15 Rotation Quaternion Z float"},{"location":"connect-field-devices/xdk-driver/#installation","title":"Installation","text":"As the others Drivers supported by Kura, it is distributed as a deployment package on the Eclipse Marketplace here. It can be installed following the instructions provided here.
"},{"location":"connect-field-devices/xdk-driver/#instance-creation","title":"Instance creation","text":"A new Xdk Driver instance can be created either by clicking the New Driver button in the dedicated Drivers and Assets Web UI section or by clicking on the +
button under Services. In both cases, the org.eclipse.kura.driver.ble.xdk
factory must be selected and a unique name must be provided for the new instance. Once instantiated, the Xdk Driver has to be configured setting the Bluetooth interface name (i.e. hci0
). Other options available are related to the quaternion/sensor representation and the sensor sampling rate (in Hz).
The Xdk Driver channel can be configured with the following parameters:
type: the channel type, (READ
, WRITE
, or READ_WRITE
).
Warning
The Xdk driver can only be used with READ.
value.type: the Java type of the channel value. The value read by the Driver will be converted to the value.type.
Apart from using the simple ActiveMQ-7 MQTT instance available in the Simple Artemis MQTT Broker Service, this service allows to configure, in a more detailed way, the characteristics of the ActiveMQ-7 broker instance running in Kura.
This service exposes the following configuration parameters:
Please refer to the official documentation for more details on how to configure the ActiveMQ broker service.
"},{"location":"core-services/active-mq-artemis-broker/#service-usage-example","title":"Service Usage Example","text":"Setting the Broker XML field as follows:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<configuration xmlns=\"urn:activemq\"\nxmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\nxsi:schemaLocation=\"\nurn:activemq https://raw.githubusercontent.com/apache/activemq-artemis/master/artemis-server/src/main/resources/schema/artemis-server.xsd\nurn:activemq:core https://raw.githubusercontent.com/apache/activemq-artemis/master/artemis-server/src/main/resources/schema/artemis-configuration.xsd\nurn:activemq:jms https://raw.githubusercontent.com/apache/activemq-artemis/master/artemis-jms-server/src/main/resources/schema/artemis-jms.xsd\n\">\n\n <core xmlns=\"urn:activemq:core\">\n <persistence-enabled>false</persistence-enabled>\n\n <acceptors>\n <acceptor name=\"netty-acceptor\">tcp://localhost:61616</acceptor>\n <acceptor name=\"amqp-acceptor\">tcp://localhost:5672?protocols=AMQP</acceptor>\n <acceptor name=\"mqtt-acceptor\">tcp://localhost:1883?protocols=MQTT</acceptor>\n </acceptors>\n\n <resolve-protocols>false</resolve-protocols>\n\n <security-settings>\n <!-- WARNING: this is only for testing and completely insecure -->\n <security-setting match=\"#\">\n <permission type=\"createDurableQueue\" roles=\"guest\"/>\n <permission type=\"deleteDurableQueue\" roles=\"guest\"/>\n <permission type=\"createNonDurableQueue\" roles=\"guest\"/>\n <permission type=\"deleteNonDurableQueue\" roles=\"guest\"/>\n <permission type=\"consume\" roles=\"guest\"/>\n <permission type=\"send\" roles=\"guest\"/>\n </security-setting>\n </security-settings>\n\n </core>\n\n <jms xmlns=\"urn:activemq:jms\">\n <topic name=\"TEST.T.1\" />\n </jms>\n\n</configuration>\n
the User configuration to:
guest=test12|guest\n
while setting the Default user name to:
guest\n
will determine that the TCP ports 1883, 5672 and 61616 are now open (you can verify that via netstat -antup).
Configuring the MqttDataTransport in System -> Cloud Services -> MqttDataTransport to use:
Clicking on the Connect button will result in a successful connection of Kura cloud service to the ActiveMQ-7 MQTT broker.
Note
The XML configuration above only allows connections originating from the gateway itself. In order to allow external connection the bind URLs specified using the acceptor
tag must be modified by specifying an external accessible address instead of localhost
. If the bind address is set to 0.0.0.0
, the broker will listen on all available addresses.
The ClockService handles the date and time management of the system. If enabled, it tries to update the system date and time using a Network Time Protocol (NTP) server. NTP can use NTS as authentication mechanism through chrony.
"},{"location":"core-services/clock-service/#service-configuration","title":"Service Configuration","text":"To manage the system date and time, select the ClockService option located in the Services area as shown in the screen capture below.
The ClockService provides the following configuration parameters:
enabled: sets whether or not this service is enabled or disabled (Required field).
clock.set.hwclock: defines if the hardware clock of the gateway must be synced after the system time is set. If enabled, the service calls the Linux command hwclock --utc --systohc
.
clock.provider: specifies one among Java NTP client (java-ntp), Linux chrony command (chrony-advanced), Linux ntpdate command (ntpd) (Required field). If chrony-advanced is used, Kura will not change system and/or hardware clock directly, delegating these operations to chrony.
clock.ntp.host: sets a valid NTP server host address.
clock.ntp.port: sets a valid NTP port number (not supported by ntpd, use the port 123 in that case).
clock.ntp.timeout: specifies the NTP timeout in milliseconds.
clock.ntp.max-retry: defines the number of retries when a sync fails (retry at every minute). Subsequently, the next retry occurs on the next refresh interval.
clock.ntp.retry.interval: defines the interval in seconds between each retry when a sync fails. If the clock.ntp.refresh-interval parameter is less than zero, there is no update. If the clock.ntp.refresh-interval parameter is equal to zero, there is only one try at startup (Required field).
clock.ntp.refresh-interval: defines the frequency (in seconds) at which the service tries to sync the clock. Note that at the start of Kura, when the ClockService is enabled, it tries to sync the clock every minute until it is successful. After a successful sync, this operation is performed at the frequency defined by this parameter. If the value is less than zero, there is no update. If the value is equal to zero, syncs only once at startup.
chrony.advanced.config: specifies the content of the chrony configuration file. If this field is left blank, the default system configuration will be used. All fields above will be ignored. To obtain the hardware clock synchronization the directive rtcsync could be used. The rtcsync directive provides the hardware clock synchronization made by the linux kernel every 11 minutes. For further information reference the chrony website.
Two example configuration are shown below.
"},{"location":"core-services/clock-service/#nts-secure-configuration-example","title":"NTS Secure configuration example","text":"server time.cloudflare.com iburst nts\nserver nts.sth1.ntp.se iburst nts\nserver nts.sth2.ntp.se iburst nts\n\nsourcedir /etc/chrony/sources.d\n\ndriftfile /var/lib/chrony/chrony.drift\n\nlogdir /var/log/chrony\n\nmaxupdateskew 100.0\n\nrtcsync\n\nmakestep 1 -1\n\nleapsectz right/UTC\n
Note
If the system stays disconnected from the network for a long time or if the backup battery is not working properly or is depleted, there is the possibility of a synchronization failure due to the client inability to verify the server certificates.
If this happens and no counter action has been taken in the chrony configuration file, the risk is that the gateway will be unable to synchronise again its date and therefore will not be able to connect to the cloud and/or be fully operational.
A possible way to prevent this issue is to temporary disable the certificate verification using the directive nocerttimecheck. This directory will disable the security checks of the activation and expiration times of certificates for the specified number of clock updates and should be used with caution due to the important security implications.
As reported by the official Chrony documentation, disabling the time checks has important security implications and should be used only as a last resort, preferably with a minimal number of trusted certificates. The default value is 0, which means the time checks are always enabled.
An example of the directive is nocerttimecheck 1
This would disable the time checks until the clock is updated for the first time, assuming the first update corrects the clock and later checks can work with correct time.
# Use public NTP servers from the pool.ntp.org project.\npool pool.ntp.org iburst\n\n# Record the rate at which the system clock gains/losses time.\ndriftfile /var/lib/chrony/drift\n\n# Allow the system clock to be stepped in the first three updates\n# if its offset is larger than 1 second.\nmakestep 1 -1\n\n# Enable kernel synchronization of the real-time clock (RTC).\nrtcsync\n
"},{"location":"core-services/command-service/","title":"Command Service","text":"The Command Service provides methods for running system commands from the Kura web console or from Kapua. In the Kura web console, the service is available clicking on the Command tab under the Device section, while for the cloud platform please refer to the official documentation.
To run a command simply fill the Execute field with the command and click the Execute button. The service also provides the ability for a script to execute using the File option of the Command tab in the Kura web console or the Kapua Cloud Console. This script must be compressed into a zip file with the eventual, associated resource files.
Once the file is selected and Execute is clicked, the zip file is sent embedded in an MQTT message on the device. The Command Service in the device stores the file in /tmp, unzips it, and tries to execute a shell script if one is present in the file. Note that in this case, the Execute parameter cannot be empty; a simple command, such as ls -l /tmp
, may be entered.
Warning
When decompressed, the script loses its executable attribute. To fix this problem, if you plan to execute a script, the command entered into the Execute line must trigger the execution: ** bash [name of the script] **.
The configuration of the service is in the CommandService tab located in the Services area as shown in the screen capture below.
The Command Service provides the following configuration parameters:
Command Enable: sets whether this service is enabled or disabled in the cloud platform (Required field).
Command Password Value: sets a password to protect this service.
Command Working Directory: specifies the working directory where the command execution is performed.
Command Timeout: sets the timeout (in seconds) for the command execution.
Command Environment: supplies a space-separated list of environment variables in the format key=value.
Privileged/Unprivileged Command Service Selection: sets the modality of the command service. When set to privileged, the commands are run using the (privileged) user that started Kura, tipically kurad or root. When set to unprivileged, a standard user will run the commands.
When a command execution is requested in the cloud platform, it sends an MQTT control message to the device requesting that the command be executed. On the device, the Command Service opens a temporary shell in the command.working.directory, sets the command.environment variables (if any), and waits command.timeout seconds to get command response.
"},{"location":"core-services/configuration-service/","title":"Configuration Service","text":"The Configuration Service is responsible to manage the framework configuration by creating and persisting the framework snapshot. Built on top of the OSGi Configuration Admin and Metatype services, it is also responsible to track and manage the creation and deletion of service instances as well as OSGi component factories.
The ConfigurationService is accessible using the following REST APIs and cloud request handlers:
Containerized applications are becoming increasingly popular in the software ecosystem as a way to deploy and distribute applications. As a result, ensuring the security of software supply chains has become a critical concern. Implementing best practices, such as signing and verifying images to mitigate man-in-the-middle (MITM) attacks and validating their authenticity and freshness, play a pivotal role in safeguarding the integrity of the software supply chain.
To ensure the authenticity and integrity of the code within the container images, binding the image to a specific entity or organization via signature verification is crucial and increasingly common.
The purpose of this document is to provide a high-level understanding of the Eclipse Kura container authenticity and allowlist enforcement feature introduced with Eclipse Kura version 5.5.0.
"},{"location":"core-services/container-orchestration-image-auth/#high-level-flow","title":"High-level flow","text":"The Eclipse Kura container authenticity and allowlist enforcement feature is designed to address container authenticity concerns by providing a mechanism to perform the signature verification of container images and restricting which container images can be deployed on the Eclipse Kura instance.
This is achieved by implementing the following flow:
Description of the flow:
This flow applies to both containers managed by Eclipse Kura itself and containers ran directly by the user via CLI, allowing for a fine-grained control over the container images that can be deployed on the Eclipse Kura instance.
Note that the user can still directly provide an image digest when running an Eclipse Kura-managed container. This will prevent the Eclipse Kura automatic signature verification process to run. This feature is meant to be used when:
Regarding the containers not managed by Eclipse Kura, the Container Orchestration service provides a security feature which enforces the containers allowed to run on the system. This feature can be enabled or disabled through the Allowlist Enforcement Enabled
option.
This mechanism leverages the concept of digest, which is a unique and immutable identifier for a container image: it is therefore an excellent mean to identify the image from which a container was created.
Given the above, Eclipse Kura allows the user to provide a list of container image digests in the Container Image Allowlist
field, in the form of newline-separated strings: when a container is started on the host system (whether it is launched by Eclipse Kura or by a terminal CLI), Eclipse Kura retrieves the image from which the container was created, extracts the digest and verifies that it is present in the allowlist provided during service configuration.
If the image digest is present and matches the container's one, it is then allowed to run without interference. Otherwise, it is immediately stopped and deleted from the host system.
A similar behaviour is performed at Eclipse Kura startup or when the enforcement is enabled at runtime: if there are already containers on the device (whether they are started or stopped) and the enforcement is activated, Eclipse Kura extracts the digests from the containers and compares them with those in the allowlist. Containers that have been created from images whose digests are in the allowlist will be left running, otherwise they will be stopped and deleted from the descriptors list.
The verification is performed by intersecting the list of digests extracted by the containers and the one provided in the configuration: in this way, an empty intersection will result in a failing verification, while a non-empty one means that the image digests is equal to one of the allowlist entries.
"},{"location":"core-services/container-orchestration-image-auth/#example-scenarios","title":"Example scenarios","text":"A user wants to leverage the container enforcement in order to let only docker containers started from an image named foo_image
to be run on the device. To do this, they should enable the Container Enforcement by setting the Allowlist Enforcement Enabled
to true
, and fill the Container Image Allowlist
field with the digest of the foo_image
docker image (i.e.sha256:0000000000000000000000000000000000000000000000000000000000000000
in the example below).
Let's suppose that on the device there are already two containers running, one created from the foo_image
an one from an image named unwanted_image
with digest sha256:9999999999999999999999999999999999999999999999999999999999999999
. Once the enforcement starts with the configuration previously described, it extracts the digests of both containers and checks if they're included in the provided allowlist: in this case, the container originating from the foo_image
will be allowed to run, while the one created from the unwanted_image
will be stopped and deleted, because its digest is not included in the allowlist.
The same happens also for already stopped containers: if the digests is verified, they'll be left in the descriptors list in the Stopped state, otherwise they'll be deleted.
"},{"location":"core-services/container-orchestration-image-auth/#running-container-after-enforcement-feature-startup","title":"Running Container After Enforcement Feature Startup","text":"After the starting phase just described, Eclipse Kura will continuously monitor the activity of the docker engine. Whenever a container is started on the device, it will check the image digest from which the container was created, comparing it to the ones inside the allowlist: if the container is created from the foo_image
docker image, it will be allowed to start, otherwise it will be stopped and deleted. If the user wants to add more than one allowed image, for example one named wanted_image
with digest sha256:1111111111111111111111111111111111111111111111111111111111111111
), it just needs to add it to the newline-separated list.
As explained in the previous section, Managed Containers (i.e. org.eclipse.kura.container.provider.ContainerInstance
s) support Container Signature validation. To do so a new API has been introduced: the ContainerSignatureValidationService
.
Currently, there are three main mechanism for container signature verification:
This newly introduced service allows Eclipse Kura to have multiple different Services implementing this interface and, thus, support all major signature mechanisms. A reference implementation for the ContainerSignatureValidationService
is the DummyContainerSignatureValidationService
available in Kura examples
folder for anyone wanting to implement an alternative ContainerSignatureValidationService
.
When a ContainerSignatureValidationService
is installed on Eclipse Kura, it gets automatically registered among the available validators and will be used to perform the signature validation. Under the hood, the ContainerInstance
has a list of the available ContainerSignatureValidationService
providers that, upon receiving a configuration update, it interrogates to check whether the requested container image is authentic using the provided Trust Anchor.
This means that Eclipse Kura doesn't need to prompt the user for selecting the correct ContainerSignatureValidationService
when performing the check.
Once the image signature is validated, the image digest is stored in the Eclipse Kura snapshot and added to the ContainerOrchestratorService
allowlist (see section above). A container whose image digest is available in the allowlist won't be validated again, therefore after the initial check, the internet connection is no longer required for it to work.
Let's suppose to have a device on which Eclipse Eclipse Kura is running with the Container Orchestration Service enabled, its Enforcement feature disabled and a Container Instance named test-container
up and running on the system.
A user wants to activate the Enforcement feature, so it enables the Allowlist Enforcement Enabled
option in the Container Orchestration Service, but leaves the Container Image Allowlist
option blank because it wants that no containers are started outside the framework.
As the feature starts, it checks all the container running on the device, including the test-container
, which will be stopped and deleted: this happens because the container digest is not included in the Container Orchestration Service Allowlist and the Container Instance is not providing any information through its Container Image Enforcement Digest
option.
In order to allow the Container Instance, the user should provide the correct digest in the instance settings. Let's suppose that the digest of the image from which the container is created is sha256:0000000000000000000000000000000000000000000000000000000000000000
and that the user fills the corresponding option with it: once the Container Instance is updated, the provided digest is included in the Enforcement feature allowlist, so the container will be allowed to run without interference. This case can be summarised as:
Once the instance digest is added to the enforcement feature, it can be used also to authorise container run by the Command Line Interface, or other instances on Eclipse Eclipse Eclipse Kura without providing the digest option. But what happen if the Container Instance is disabled? The aim of the Container Instance Enforcement Digest is to be used as an authorization method of the instance itself: this means that its digest is added to the enforcement feature allowlist only if the instance is enabled.
As it can be seen from the image, the merged Enforcement Allowlist
box doesn't contain the digest associated to the Container Instance, because, being it disabled, the corresponding digest is ignored. If the enforcement is enabled and a container with digest DIGEST Z is started, it will then be stopped and deleted, because its digest won't be included in the allowlist.
Finally, everytime a Container Image Enforcement Digest option is modified, or the ContainerInstance is disabled or deleted, the enforcement feature will perform a check on all the already running containers. This is done because, if the digest that was previously provided has changed after an instance update, or removed due to disabling or deleting the instance, those containers that were previously authorised by this digest are no longer allowed to run. So they must be stopped and deleted.
Warning
The digests provided through Container Instances allow running also container started by the CommandLineInterface or by other Container Instances in the framework, even without providing the digest.
It has to be considered that, if the ContainerInstance is disabled (or its digest option changes), the enforcement feature will stop and delete the containers that are no longer matching the provided digest.
The user needs to be careful, then, to rely only on the digests set in the ContainerInstances options. If the user will need to run containers from the CLI, it is preferable to use the allowlist of the Container Orchestration Service. For the Container Instances, is a good practise to provide a digest.
"},{"location":"core-services/container-orchestration-image-auth/#container-signature-verification","title":"Container Signature Verification","text":"If the Container Image Enforcement Digest option is not provided, Eclipse Eclipse Kura will proceed with the Signature Verification: this process tries to extract the digest of the image from which the container was started.
Let's then suppose that we are back at the beginning of the previous example, with a blank Container Orchestration Service allowlist and a not given Container Instance Digest, but this time a Trust Anchor option is given: in this case Eclipse Eclipse Kura will start the Signature Verification Process, in order to extract the digest.
If, for whatever reason, the Signature Verification fails, no digests will be added to the allowlist: if the enforcement feature is enabled, the started container will be then stopped and deleted by the Enforcement Monitor, because no digests are included in the final Enforcement Allowlist.
While, if the procedure completes correctly, the extracted digest will be added to the Enforcement Allowlist and written in the snapshot: in this way the container will pass the enforcement feature check, and the obtained digest will be stored as part of the Container Instance's configuration just started.
If the user wants to check again the digest through the Signature Verification Service, it just needs to erase the Container Image Enforcement Digest option from the configuration of the Container Instance: in this way the Signature feature will be triggered again and the digest recalculated.
Warning
Even in this situation, the digest could be used to authenticate container started from the CommandLineInterface: also in this case keep in mind that if the Container Instance is disabled, stopped or updated with different digest, those CLI-based container could be stopped and deleted.
"},{"location":"core-services/container-orchestration-provider-apis/","title":"Container Orchestration Provider APIs","text":""},{"location":"core-services/container-orchestration-provider-apis/#java-api","title":"Java API","text":""},{"location":"core-services/container-orchestration-provider-apis/#containerorchestrationservice","title":"ContainerOrchestrationService","text":"The ContainerOrchestrationService is used to directly communicate with the running container engine. It exposes methods for listing, creating, and stopping containers. This class utilizes an instantiated ContainerConfiguration object as a parameter for container creation.
"},{"location":"core-services/container-orchestration-provider-apis/#containerconfiguration","title":"ContainerConfiguration","text":"The ContainerConfiguration class, allows you to define a container to create. Using the embedded builder class, one can define many container-related parameters such as name, image, ports and volume mounts.
"},{"location":"core-services/container-orchestration-provider-apis/#containerinstancedescriptor","title":"ContainerInstanceDescriptor","text":"The ContainerInstanceDescriptor class is used to describe a container that has already been created. This class contains runtime information such as the ID of the container.
"},{"location":"core-services/container-orchestration-provider-apis/#containerstate","title":"ContainerState","text":"The ContainerState is a class that exposes an enum of container states tracked by the framework.
"},{"location":"core-services/container-orchestration-provider-apis/#passwordregistrycredentials","title":"PasswordRegistryCredentials","text":"The PasswordRegistryCredentials class stores password credentials when provisioning a container to pull from an alternative password-protected registry.
"},{"location":"core-services/container-orchestration-provider-apis/#passwordregistrycredentials_1","title":"PasswordRegistryCredentials","text":"The PasswordRegistryCredentials class stores password credentials when provisioning a container to pull from an alternative password-protected registry.
Note
The Container Orchestration Provider exports an MQTT-Namespace API. This API can be used to manage containers via MQTT requests from external applications. Please visit the Remote Gateway Inventory via MQTT documentation for more information.
"},{"location":"core-services/container-orchestration-provider-authenticated-registries/","title":"Container Orchestration Provider Authenticated Registries","text":"The Container Orchestrator provider allows the user to pull images from private and password-protected registries. The following document will provide examples of how to connect to some popular registries.
Note
These guides make the following two assumptions.
**Image Name: ** <Docker-Hub username>/<image name>
for exampleeclipse/kura
.
Populate the credential fields:
Sign in to your amazon web console, navigate to ECR and identify which container you will like to pull onto the gateway. Copy the URI of the container. This URI will reveal the information required for the following steps. Here is how to decode the URI <identifier>.dkr.ecr.<ecr-region>.amazonaws.com/<directory>/<image name>:<image tag>
.
Generating an AWS-ECR access password. Open a terminal window on the machine with aws-cli installed and enter the following command aws ecr get-login-password --region <ecr-region>
. Your ECR region can be found by inspecting the container URI string copied in the previous step. This command will return a long string which will be used as the repo password in the gateway.
Populating information on the gateway.
<identifier>.dkr.ecr.<ecr-region>.amazonaws.com/<directory>/<image name>
<image tag>
<identifier>.dkr.ecr.<ecr-region>.amazonaws.com/<directory>/
AWS
A fully configured container set to pull AWS will look like the following.
"},{"location":"core-services/container-orchestration-provider-usage/","title":"Container Orchestration Provider Usage","text":""},{"location":"core-services/container-orchestration-provider-usage/#before-starting","title":"Before Starting","text":"For this bundle to function appropriately, the gateway must have a supported container engine installed and running. Currently, the only officially supported engine is Docker.
"},{"location":"core-services/container-orchestration-provider-usage/#starting-the-service","title":"Starting the Service","text":"To use this service select the ContainerOrchestrationService option located in the Services area. The ContainerOrchestrationService provides the following parameters:
To create a container, select the +
icon (Create a new component) under services. A popup dialogue box will appear. In the field Factory select org.eclipse.kura.container.provider.ContainerInstance from the drop-down. Then, use the Name field to specify a name for the container.
Note
The name specified in the 'Name' field will also be the name of the container when it is spun up by the orchestrator.
After pressing submit, a new component will be added under the services tab, with the name that was selected in the dialogue. Select this component to finish configuring the container.
"},{"location":"core-services/container-orchestration-provider-usage/#configuring-the-container","title":"Configuring the container","text":"To begin configuring the container, look under Services and select the item which has the name set in the previous step. Containers may be configured using the following fields:
Enabled - When true, the service will create the defined container. When false the API will not create the container or will destroy the container if already running.
Image Name - Describes the image that will be used to create the container. Remember to ensure that the selected image supports the architecture of the host machine, or else the container will not be able to start.
Image Tag - Describes the version of the container image that will be used to create the container.
Trust Anchor - Trust anchor used to verify the container image Signature Verification
Verify in transparency log - Sets the transparency log verification, to be used when a container image signature has been uploaded to the transparency log.
Container Image Enforcement Digest - A string representing the digest for the image that will be allowed to run by this container instance (eg: sha256:0000000000000000000000000000000000000000000000000000000000000000
). It is used in the Container Enforcement service provided by the Container Orchestration Service.
Authentication Registry URL - URL for an alternative registry to pull images from. (If the field is left blank, credentials will be applied to Docker-Hub). Please see the Authenticated Registries document for more information about connecting to different popular registries.
Authentication Username - Describes the username to access the container registry entered above.
Password - Describes the password to access the alternative container registry.
Image Download Retries - Describes the number of retries the framework will attempt to pull the image before giving up.
Image Download Retry Interval - Describes the amount of time the framework will wait before attempting to pull the image again.
Image Download Timeout - Describes the amount of time the framework will let the image download before timeout.
Internal Ports - This field accepts a comma-separated list of ports that will be internally exposed on the spun-up container. In this field, you can also specify which protocol to run at the port by appending a port with a colon and typing in the name of the network protocol. Example: 80, 443:tcp, 8080:udp
.
External Ports - This field accepts a comma-separated list of ports that will be externally exposed on the host machine.
Privileged Mode - This flag if enabled will give the container root capabilities to all devices on the host system. Please be aware that setting this flag can be dangerous, and must only be used in exceptional situations.
Environment Variables (optional) - This field accepts a comma-separated list of environment variables, which will be set inside the container when spun up.
Entrypoint Override (optional) - This field accepts a comma-separated list which is used to override the command used to start a container. Example: ./test.sh,-v,-d,--human-readable
.
Memory (optional) - This field allows the configuration of the maximum amount of memory the container can use in bytes. The value is a positive integer, optionally followed by a suffix of b, k, m, g, to indicate bytes, kilobytes, megabytes, or gigabytes. The minimum and default values depends by the native container orchestrator. If left empty, the memory assigned to the container will be set to a default value.
CPUs (optional) - This value specifies how many CPUs a container can use. Decimal values are allowed, so if set to 1.5, the container will use at most one and a half cpu resource.
GPUs (optional) - This field configures how many Nvidia GPUs a container can use. Allowed values are all
or an integer number. If there's no Nvidia GPU installed, leave it empty. The Nvidia Container Toolkit must be installed on the system to correctly configure the service, otherwise the container will not start. If the Nvidia Container Runtime is used, leave the field empty.
Volume Mount (optional) - This field accepts a comma-separated list of system-to-container file mounts. This allows for the container to access files on the host machine.
Peripheral Device (optional) - This field accepts a comma-separated list of device paths. This parameter allows devices to be passed through from the host to the container.
Runtime (optional): Specifies the fully qualified name of an alternate OCI-compatible runtime, which is used to run commands specified by the 'run' instruction. Example: nvidia
corresponds to --runtime=nvidia
. Note: when using the Nvidia Container Runtime, leave the GPUs field empty. The GPUs available on the system will be accessible from the container by default.
Networking Mode (optional) - Use this field to specify what networking mode the container will use. Possible Drivers include: bridge, none, container:{container id}, host. Please note that this field is case-sensitive. This field can also be used to connect to any of the networks listed by the cli command docker network ls
.
Logger Type - This field provides a drop-down selection of supported container logging drivers.
Logger Parameters (optional) - This field accepts a comma-separated list of logging parameters. More information can be found in the container-engine logger documentation, for instance here.
Restart Container On Failure - A boolean that tells the container engine to automatically restart the container when it has failed or shut down.
After specifying container parameters, ensure to set Enabled to true and press Apply. The container engine will then pull the respective image, spin up and start the container. If the gateway or the framework is power cycled, and the container and Container Orchestration Service are set to enabled, the framework will automatically start the container again upon startup.
"},{"location":"core-services/container-orchestration-provider-usage/#stopping-the-container","title":"Stopping the container","text":"Warning
Stopping a container will delete it in an irreversible way. Please be sure to only use stateless containers and/or save their data in external volumes.
To stop the container without deleting the component, set the Enabled field to false, and then press Apply. This will delete the running container, but leave this component available for running the container again in the future. If you want to completely remove the container and component, press the Delete button to the top right of the screen, and press Yes on the confirmation dialogue.
"},{"location":"core-services/container-orchestration-provider-usage/#container-management-dashboard","title":"Container Management Dashboard","text":"The Container Orchestration service also provides the user with an intuitive container dashboard. This dashboard shows all containers running on a gateway, including containers created with the framework and those created manually through the command-line interface. To utilize this dashboard the org.eclipse.container.orchestration.provider
(ContainerOrchestrationService) must be enabled, and the dashboard can be opened by navigating to Device > Containers.
The Container Orchestration Provider allows Kura to manage Docker. With this tool, you can arbitrarily pull and deploy containerized software packages and run them on your gateway. This Service allows the user to create, configure, start, and stop containers all from the browser. The bundle will also restart containers if the gateway is restarted.
The feature is composed of two bundles, one that exposes APIs for container management and one that implements those APIs. This API is exposed so that you can leverage it to implement containerization in your own Kura plugins.
"},{"location":"core-services/deployment-service/","title":"Deployment Service","text":"The Deployment Service allows to download files to the gateway and to perform actions on them. In the configuration tab it is possible to specify which is the directory that has to be used to store the downloaded files and the list of actions declared as deployment hooks that will be invoked when a corresponding metric is received with the download request.
The configuration requires to specify two parameters:
<request_type>=<hook_pid>
, where <hook_pid>
is the Kura Service Pid of a DeploymentHook instance and <request_type>
is the value of the request.type metric received with the request.Kura can detect changes to the components and publish them using a selected Cloud Publisher. There are two main components that enable this:
org.eclipse.kura.configuration.change.manager
, andorg.eclipse.kura.event.publisher
The org.eclipse.kura.configuration.change.manager
is responsible for detecting changes to any of the configurations currently running on the system and to publish a notification to a user-defined cloud publisher. By default, the org.eclipse.kura.event.publisher
is used.
The configuration change manager allows to collection of the PIDs of the components that have changed in the system. The configurable properties of this component are:
The collected PIDs are sent to the Cloud Publisher as a KuraMessage
with a payload body in JSON format. The timestamp of the KuraMessage
is set to the last detected configuration change event. An example of message body is:
[\n {\n \u201cpid\u201d: \u201corg.eclipse.kura.clock.ClockService\u201d\n },\n {\n \u201cpid\u201d: \u201corg.eclipse.kura.log.filesystem.provider.FilesystemLogProvider\u201d\n }\n]\n
In the example above, a ClockService update triggered the delay timer, which was then reset by a configuration update on the FilesystemLogProvider. Afterward, no configuration updates reset the timer so the message containing the two PIDs was sent after expiration.
"},{"location":"core-services/device-configuration-changes/#event-publisher","title":"Event Publisher","text":"By default, the org.eclipse.kura.event.publisher
used by the configuration change manager does the actual publishing on a user-defined topic of the form:
$EVT/#account_id/#client_id/CONF/V1/CHANGE
This topic is adjusted for integration with EC, but the $EVT
and the CONF/V1/CHANGE
parts can be customized according to user needs by tweaking the Topic prefix and Topic properties.
The #account_id
and #client_id
fields are substituted at runtime with the account name and client ID at the Data Transport Service layer of the associated Cloud Connection.
The Qos, Retain, and Priority properties are the usual ones defined in the standard Cloud Publisher.
"},{"location":"core-services/h2db-service/","title":"H2Db Service","text":"Kura integrates a Java SQL database named H2. The main features of this SQL Database are:
Kura supports the following H2 database features:
Persistence modes: The H2 implementation currently supports in-memory and file-based database instances. See the Persistence Modes section for more details.
Multiple database instances: It is possible to create and configure multiple database instances from the Kura Administration UI, these instances can be selectively consumed by applications. A default database instance is created automatically.
TCP Server: The current implementation allows external processes to access the database instances managed by Kura using TCP. This enables the integration of external applications that can share data with Kura components using the database.
Web-based console: It is possible to start the H2 Web console directly from the Kura Administration UI. The console can be used to inspect the database contents and perform arbitrary queries for debug purposes.
Basic credential management: The current implementation allows to change the password of the admin DB user from the Kura Administration UI. This allows the access restriction to the existing database instances.
By default, the DataService in Kura uses the H2 database to persist the messages.
"},{"location":"core-services/h2db-service/#limitations","title":"Limitations","text":"Private in-memory instances: Only named in-memory instances are supported (e.g. jdbc:h2:mem:<dbname>
, where <dbname>
is not the empty string), private instances represented by the jdbc:h2:mem:
URL are currently not supported.
Remote connections: The current implementation only supports embedded database instances. Connecting to remote instances using the jdbc:h2:tcp:*
and jdbc:h2:ssl:*
connector URLs is not supported.
Note
The new DbWireRecordFilter
and DbWireRecordStore
Wire components have been added. These components provide the same functionalities offered by the old H2DbWireRecordFilter
and H2DbWireRecordStore
components, but they can be used for connectiong to a generic relational database (i.e. H2DB, MySQL or MariaDB). The legacy components will continue to be available in order to keep backward compatibility, but will be deprecated since Kura 5.2.0 and should not be used for new installations.
To create a new H2 database instance, use the following procedure:
org.eclipse.kura.core.db.H2DbService
from the Factory drop-down list, enter an arbitrary name for the new instance and click Apply. The H2DbService provides the following configuration parameters:
Warning
If the database is created in persisted mode, please make sure that the Linux user running Eclipse Kura has the permissions required to create the database file. If the permissions are not ok, Eclipse Kura may be able to create the database (by default it runs with the CAP_DAC_OVERRIDE capability) but it may not be able to perform the periodic defragmentation process, this may cause the database file size to grow expecially if the write rate is high.
Executing the following commands as root
can be useful to detect potential issues, replace database_parent_directory
with the parent directory of the database file and kura_linux_user
with the Linux user that is executing Eclipse Kura (e.g. kurad):
export TARGET=\"$(readlink -f database_parent_directory)\"\nexport KURA_USER=\"kura_linux_user\"\nsudo -u \"${KURA_USER}\" sh -c \"touch '${TARGET}/.testfile' && rm '${TARGET}/.testfile'\"\n
If command fails it may be necessary to change the database directory or adjust the permissions.
User: Specifies the user for the database connection. Furthermore
Password: Specifies the password. The default password is the empty string.
Checkpoint interval (seconds): H2DbService instances support running periodic checkpoints to ensure data consistency. This parameter specifies the interval in seconds between two successive checkpoints. This setting has no effect for in-memory database instances.
Defrag interval (minutes): H2DbService instances support running periodic defragmentation (compaction). This parameter specifies the interval in minutes between two successive checkpoints, set to zero to disable. This setting has no effect for in-memory database instances. Existing database connections will be closed during the defragmentation process and need to be reopened by the applications.
Connection pool max size: The H2DbService manages connections using a connection pool. This parameter defines the maximum number of connections for the pool
A database instance is identified by its Kura service PID. The PID for the default instance is org.eclipse.kura.db.H2DbService
while the PID for instances created using the Web UI is the string entered in the Name field at step 2 of the previous section.
The built-in components that use database functionalities allow to specify which instance to use in their configuration. These components are the DataService component of the cloud stack, the DbWireRecordFilter and DbWireRecordStore wire components. The configuration of each component contains a property that allows to specify the service PID of the desired instance.
"},{"location":"core-services/h2db-service/#usage-through-wires","title":"Usage through Wires","text":"It is possible to store and extract Wire Records into/from a H2 database instance using the Wire Record Store and Wire Record Query wire components.
When a Wire Record is received by a Wire Record Store attached to a H2 based database instance, the data will be stored in a table whose name is the current value of the Record Collection Name configuration parameter of the Wire Component.
Each property contained in a Wire Record will be appended to a column with the same name as the property key. A new column will be created if it doesn't already exists.
Note
Storing wire record properties with the FLOAT data type using the Wire Record Store is not recommended since the type information will be lost. Values inserted as FLOAT using the Wire Record Store will be retrieved as DOUBLE using the Wire Record Query component.
Warning
It is not recommended to store Wire Records having properties with the same key and different value type. If the value type changes, the target column will be dropped and recreated with the type derived from the last received record. All existing data in the target column will be lost. The purpose of this is to allow changing the type of a column with a Wire Graph configuration update.
"},{"location":"core-services/h2db-service/#enabling-the-tcp-server","title":"Enabling the TCP Server","text":"Danger
This feature is intended to be used only for debugging/development purposes. The server created by H2 is not running on a secure protocol. Only enable the server for a limited time and make sure to properly secure the firewall ports on which it is running.
The TCP server can be used by creating a H2DbServer instance:
org.eclipse.kura.core.db.H2DbServer
from the Factory drop-down\u200b list, enter an arbitrary name for the new instance and click Apply.The server, with the default configuration, will be listening on port 9123.
Tip
Make sure to review the firewall configuration in order to ensure that the server is reachable from an external process.
"},{"location":"core-services/h2db-service/#enabling-the-web-console","title":"Enabling the Web Console","text":"Danger
This feature is intended to be used only for debugging/development purposes. The server created by H2 is not running on a secure protocol. Only enable the server for a limited time and make sure to properly secure the firewall ports on which it is running.
In order to enable the H2 Web console, proceed as follows:
-webPort 9123 -webAllowOthers -ifExists -webExternalNames <device-ip>
.The server is now listening on the specified port.
Tip
Make sure to review the firewall configuration in order to ensure that the server is reachable from an external process.
Use a browser to access the console. Open the http://: URL, where is the IP address of the gateway and is the port specified at step 3.
Enter the DB URL as specified in the Kura configuration in the JDBC URL field and the credentials. Click on Connect, you should be able to access the console.
"},{"location":"core-services/h2db-service/#change-the-database-password","title":"Change the Database Password","text":"To change the database password the System Administrator needs to:
Warn
If the H2DbServer instance fails to open a database, it will delete and recreate all database files. This behavior\u200b is aimed at preventing potential issues caused by incorrect credentials in the configuration snapshots. It is highly recommended to perform a backup of an existing database before trying to open it using a H2DbService instance and before changing the password.
"},{"location":"core-services/h2db-service/#persistence-modes","title":"Persistence Modes","text":"The H2 database supports several persistence modes.
"},{"location":"core-services/h2db-service/#in-memory","title":"In Memory","text":"An in-memory database instance can be created using the following URL structure: jdbc:h2:mem:, where is a non-empty string that represents the database name. This configuration is suggested for database instances that are frequently updated. Examples:
The default database instance is in-memory by default and uses the jdbc:h2:mem:kuradb URL.
"},{"location":"core-services/h2db-service/#persistent","title":"Persistent","text":"A persistent database instance can be created using the jdbc:h2:file:, where is a non-empty string that represents the database path.
If no URL parameters are supplied the database will enable the transaction log by default. The transaction log is used to restore the database to a consistent state after a crash or power failure. This provides good protection against data losses but causes a lot of writes to the storage device, reducing both performance and the lifetime of flash-based storage devices.
Examples: - jdbc:h2:file:/opt/db/mydb
Make sure to use absolute paths in the DB URL since H2 does not support DB paths relative to the working directory.
"},{"location":"core-services/introduction/","title":"Introduction","text":"This section describes the administrative tools available using the Gateway Administration Console. This web interface provides the ability to configure all services and applications that are installed and running on the gateway.
"},{"location":"core-services/network-status-rest-v1/","title":"Network Status Service V1 REST APIs and MQTT Request Handler","text":"The NET-STATUS-V1 cloud request handler and the corresponding REST APIs allow to retrieve the current status of the network interfaces available on the system.
This cloud request handler and rest API is available only on the systems that provide a NetworkStatusService implementation, at the moment this corresponds to the devices that include the NetworkManager integration.
Accessing the REST APIs requires to use an identity with the rest.network.status
permission assigned.
failures
field of the response.failures
field of the responses.interfaceIds
field, it is null
or if it contains empty or null
interface ids.An object containing a list of network interface identifiers
Properties:
interfaceIds: array
The list of network interface identifiers
string
An interface identifier{\n \"interfaceIds\": [\n \"lo\"\n ]\n}\n
"},{"location":"core-services/network-status-rest-v1/#interfacestatuslist","title":"InterfaceStatusList","text":"An object reporting a list of network interface status. If a failure occurs retrieving the status for a specific interface, the reason will be reported in the failures
list.
Properties:
interfaces: array
A list of network interface status
variant
failures: array
object
{\n \"failures\": [],\n \"interfaces\": [\n {\n \"autoConnect\": true,\n \"driver\": \"unknown\",\n \"driverVersion\": \"\",\n \"firmwareVersion\": \"\",\n \"hardwareAddress\": \"00:00:00:00:00:00\",\n \"id\": \"lo\",\n \"interfaceIp4Addresses\": {\n \"addresses\": [\n {\n \"address\": \"127.0.0.1\",\n \"prefix\": 8\n }\n ],\n \"dnsServerAddresses\": []\n },\n \"interfaceName\": \"lo\",\n \"mtu\": 65536,\n \"state\": \"UNMANAGED\",\n \"type\": \"LOOPBACK\",\n \"virtual\": true\n }\n ]\n}\n
{\n \"failures\": [\n {\n \"interfaceId\": \"foo\",\n \"reason\": \"Not found.\"\n }\n ],\n \"interfaces\": []\n}\n
"},{"location":"core-services/network-status-rest-v1/#loopbackinterfacestatus","title":"LoopbackInterfaceStatus","text":"Object that contains specific properties to describe the status of an Loopback interface. It contains also all of the properties specified by NetworkInterfaceStatus.
Properties:
{\n \"autoConnect\": true,\n \"driver\": \"unknown\",\n \"driverVersion\": \"\",\n \"firmwareVersion\": \"\",\n \"hardwareAddress\": \"00:00:00:00:00:00\",\n \"id\": \"lo\",\n \"interfaceIp4Addresses\": {\n \"addresses\": [\n {\n \"address\": \"127.0.0.1\",\n \"prefix\": 8\n }\n ],\n \"dnsServerAddresses\": []\n },\n \"interfaceName\": \"lo\",\n \"mtu\": 65536,\n \"state\": \"UNMANAGED\",\n \"type\": \"LOOPBACK\",\n \"virtual\": true\n}\n
"},{"location":"core-services/network-status-rest-v1/#ethernetinterfacestatus","title":"EthernetInterfaceStatus","text":"Object that contains specific properties to describe the status of an Ethernet interface. It contains also all of the properties specified by NetworkInterfaceStatus.
Properties:
bool
{\n \"autoConnect\": true,\n \"driver\": \"igb\",\n \"driverVersion\": \"5.6.0-k\",\n \"firmwareVersion\": \"3.25, 0x800005d0\",\n \"hardwareAddress\": \"00:E0:C7:0A:5F:89\",\n \"id\": \"eno1\",\n \"interfaceIp4Addresses\": {\n \"addresses\": [\n {\n \"address\": \"172.16.0.1\",\n \"prefix\": 24\n }\n ],\n \"dnsServerAddresses\": [],\n \"gateway\": \"0.0.0.0\"\n },\n \"interfaceName\": \"eno1\",\n \"linkUp\": true,\n \"mtu\": 1500,\n \"state\": \"ACTIVATED\",\n \"type\": \"ETHERNET\",\n \"virtual\": false\n}\n
"},{"location":"core-services/network-status-rest-v1/#wifiinterfacestatus","title":"WifiInterfaceStatus","text":"Object that contains specific properties to describe the status of a WiFi interface. It contains also all of the properties specified by NetworkInterfaceStatus.
Properties:
capabilities: array
string (enumerated)
channels: array
object
countryCode: string
mode: string (enumerated)
activeWifiAccessPoint: object
(optional)
availableWifiAccessPoints: array
object
{\n \"activeWifiAccessPoint\": {\n \"channel\": {\n \"channel\": 11,\n \"frequency\": 2462\n },\n \"hardwareAddress\": \"11:22:33:44:55:66\",\n \"maxBitrate\": 130000,\n \"mode\": \"INFRA\",\n \"rsnSecurity\": [\n \"GROUP_CCMP\",\n \"KEY_MGMT_PSK\",\n \"PAIR_CCMP\"\n ],\n \"signalQuality\": 100,\n \"signalStrength\": -20,\n \"ssid\": \"MyAccessPoint\",\n \"wpaSecurity\": [\n \"NONE\"\n ]\n },\n \"autoConnect\": true,\n \"availableWifiAccessPoints\": [\n {\n \"channel\": {\n \"channel\": 11,\n \"frequency\": 2462\n },\n \"hardwareAddress\": \"11:22:33:44:55:66\",\n \"maxBitrate\": 130000,\n \"mode\": \"INFRA\",\n \"rsnSecurity\": [\n \"GROUP_CCMP\",\n \"KEY_MGMT_PSK\",\n \"PAIR_CCMP\"\n ],\n \"signalQuality\": 100,\n \"signalStrength\": -20,\n \"ssid\": \"MyAccessPoint\",\n \"wpaSecurity\": [\n \"NONE\"\n ]\n },\n {\n \"channel\": {\n \"channel\": 5,\n \"frequency\": 2432\n },\n \"hardwareAddress\": \"22:33:44:55:66:77\",\n \"maxBitrate\": 270000,\n \"mode\": \"INFRA\",\n \"rsnSecurity\": [\n \"GROUP_CCMP\",\n \"KEY_MGMT_PSK\",\n \"PAIR_CCMP\"\n ],\n \"signalQuality\": 42,\n \"signalStrength\": -69,\n \"ssid\": \"OtherSSID\",\n \"wpaSecurity\": [\n \"NONE\"\n ]\n }\n ],\n \"capabilities\": [\n \"CIPHER_WEP40\",\n \"WPA\",\n \"AP\",\n \"FREQ_VALID\",\n \"ADHOC\",\n \"RSN\",\n \"CIPHER_TKIP\",\n \"CIPHER_WEP104\",\n \"CIPHER_CCMP\",\n \"FREQ_2GHZ\"\n ],\n \"channels\": [\n {\n \"attenuation\": 20.0,\n \"channel\": 1,\n \"disabled\": false,\n \"frequency\": 2412,\n \"noInitiatingRadiation\": false,\n \"radarDetection\": false\n },\n {\n \"attenuation\": 20.0,\n \"channel\": 2,\n \"disabled\": false,\n \"frequency\": 2417,\n \"noInitiatingRadiation\": false,\n \"radarDetection\": false\n }\n ],\n \"countryCode\": \"IT\",\n \"driver\": \"brcmfmac\",\n \"driverVersion\": \"7.45.98.94\",\n \"firmwareVersion\": \"01-3b33decd\",\n \"hardwareAddress\": \"44:55:66:77:88:99\",\n \"id\": \"wlan0\",\n \"interfaceIp4Addresses\": {\n \"addresses\": [\n {\n \"address\": \"192.168.0.113\",\n \"prefix\": 24\n }\n ],\n \"dnsServerAddresses\": []\n },\n \"interfaceName\": \"wlan0\",\n \"mode\": \"INFRA\",\n \"mtu\": 1500,\n \"state\": \"ACTIVATED\",\n \"type\": \"WIFI\",\n \"virtual\": false\n}\n
{\n \"activeWifiAccessPoint\": {\n \"channel\": {\n \"channel\": 1,\n \"frequency\": 2412\n },\n \"hardwareAddress\": \"44:55:66:77:88:99\",\n \"maxBitrate\": 0,\n \"mode\": \"INFRA\",\n \"rsnSecurity\": [\n \"GROUP_CCMP\",\n \"KEY_MGMT_PSK\",\n \"PAIR_CCMP\"\n ],\n \"signalQuality\": 0,\n \"signalStrength\": -104,\n \"ssid\": \"kura_gateway_raspberry_pi\",\n \"wpaSecurity\": [\n \"NONE\"\n ]\n },\n \"autoConnect\": true,\n \"availableWifiAccessPoints\": [\n {\n \"channel\": {\n \"channel\": 1,\n \"frequency\": 2412\n },\n \"hardwareAddress\": \"44:55:66:77:88:99\",\n \"maxBitrate\": 0,\n \"mode\": \"INFRA\",\n \"rsnSecurity\": [\n \"GROUP_CCMP\",\n \"KEY_MGMT_PSK\",\n \"PAIR_CCMP\"\n ],\n \"signalQuality\": 0,\n \"signalStrength\": -104,\n \"ssid\": \"kura_gateway_raspberry_pi\",\n \"wpaSecurity\": [\n \"NONE\"\n ]\n }\n ],\n \"capabilities\": [\n \"CIPHER_WEP40\",\n \"WPA\",\n \"AP\",\n \"FREQ_VALID\",\n \"ADHOC\",\n \"RSN\",\n \"CIPHER_TKIP\",\n \"CIPHER_WEP104\",\n \"CIPHER_CCMP\",\n \"FREQ_2GHZ\"\n ],\n \"channels\": [\n {\n \"attenuation\": 20.0,\n \"channel\": 1,\n \"disabled\": false,\n \"frequency\": 2412,\n \"noInitiatingRadiation\": false,\n \"radarDetection\": false\n },\n {\n \"attenuation\": 20.0,\n \"channel\": 2,\n \"disabled\": false,\n \"frequency\": 2417,\n \"noInitiatingRadiation\": false,\n \"radarDetection\": false\n }\n ],\n \"countryCode\": \"00\",\n \"driver\": \"brcmfmac\",\n \"driverVersion\": \"7.45.98.94\",\n \"firmwareVersion\": \"01-3b33decd\",\n \"hardwareAddress\": \"44:55:66:77:88:99\",\n \"id\": \"wlan0\",\n \"interfaceIp4Addresses\": {\n \"addresses\": [\n {\n \"address\": \"172.16.1.1\",\n \"prefix\": 24\n }\n ],\n \"dnsServerAddresses\": []\n },\n \"interfaceName\": \"wlan0\",\n \"mode\": \"MASTER\",\n \"mtu\": 1500,\n \"state\": \"ACTIVATED\",\n \"type\": \"WIFI\",\n \"virtual\": false\n}\n
"},{"location":"core-services/network-status-rest-v1/#modeminterfacestatus","title":"ModemInterfaceStatus","text":"Object that contains specific properties to describe the status of a Modem interface. It contains also all of the properties specified by NetworkInterfaceStatus.
Properties:
model: string
manufacturer: string
serialNumber: string
softwareRevision: string
hardwareRevision: string
primaryPort: string
ports: object
supportedModemCapabilities: array
string (enumerated)
currentModemCapabilities: array
string (enumerated)
powerState: string (enumerated)
supportedModes: array
object
currentModes: object
supportedBands: array
string (enumerated)
currentBands: array
string (enumerated)
gpsSupported: bool
availableSims: array
object
simLocked: bool
bearers: array
object
connectionType: string (enumerated)
connectionStatus: string (enumerated)
accessTechnologies: array
string (enumerated)
signalQuality: number
signalStrength: number
registrationStatus: string (enumerated)
operatorName: string
{\n \"accessTechnologies\": [\n \"LTE\"\n ],\n \"autoConnect\": true,\n \"availableSims\": [\n {\n \"active\": true,\n \"primary\": true,\n \"eSimStatus\": \"UNKNOWN\",\n \"eid\": \"\",\n \"iccid\": \"1111111111111111111\",\n \"imsi\": \"111111111111111\",\n \"operatorName\": \"MyOperator\",\n \"operatorIdentifier\": \"12345\",\n \"simType\": \"PHYSICAL\"\n }\n ],\n \"bearers\": [\n {\n \"apn\": \"apn.myoperator.com\",\n \"bytesReceived\": 0,\n \"bytesTransmitted\": 0,\n \"connected\": true,\n \"ipTypes\": [\n \"IPV4\"\n ],\n \"name\": \"wwp11s0f2u3i4\"\n }\n ],\n \"connectionStatus\": \"CONNECTED\",\n \"connectionType\": \"DirectIP\",\n \"currentBands\": [\n \"DCS\",\n \"EUTRAN_3\",\n \"EUTRAN_19\",\n \"EUTRAN_40\",\n \"EUTRAN_26\",\n \"EUTRAN_28\",\n \"EUTRAN_41\",\n \"UTRAN_6\",\n \"EUTRAN_13\",\n \"EUTRAN_25\",\n \"EUTRAN_5\",\n \"EUTRAN_7\",\n \"EUTRAN_8\",\n \"UTRAN_2\",\n \"EUTRAN_38\",\n \"UTRAN_1\",\n \"EUTRAN_12\",\n \"UTRAN_8\",\n \"EUTRAN_18\",\n \"UTRAN_19\",\n \"G850\",\n \"EUTRAN_20\",\n \"UTRAN_5\",\n \"EUTRAN_1\",\n \"EUTRAN_39\",\n \"EUTRAN_2\",\n \"EUTRAN_4\",\n \"EGSM\",\n \"PCS\",\n \"UTRAN_4\"\n ],\n \"currentModemCapabilities\": [\n \"GSM_UMTS\",\n \"LTE\"\n ],\n \"currentModes\": {\n \"modes\": [\n \"MODE_2G\",\n \"MODE_3G\",\n \"MODE_4G\"\n ],\n \"preferredMode\": \"MODE_4G\"\n },\n \"driver\": \"qmi_wwan, option1\",\n \"driverVersion\": \"\",\n \"firmwareVersion\": \"\",\n \"gpsSupported\": true,\n \"hardwareAddress\": \"00:00:00:00:00:00\",\n \"hardwareRevision\": \"10000\",\n \"id\": \"1-3\",\n \"interfaceIp4Addresses\": {\n \"addresses\": [\n {\n \"address\": \"1.2.3.4\",\n \"prefix\": 30\n }\n ],\n \"dnsServerAddresses\": [\n \"1.2.3.6\",\n \"1.2.3.7\"\n ],\n \"gateway\": \"1.2.3.5\"\n },\n \"interfaceName\": \"wwp11s0f2u3i4\",\n \"manufacturer\": \"QUALCOMM INCORPORATED\",\n \"model\": \"QUECTEL Mobile Broadband Module\",\n \"mtu\": 1500,\n \"operatorName\": \"MyOperator\",\n \"ports\": {\n \"cdc-wdm0\": \"QMI\",\n \"ttyUSB0\": \"QCDM\",\n \"ttyUSB1\": \"GPS\",\n \"ttyUSB2\": \"AT\",\n \"ttyUSB3\": \"AT\",\n \"wwp11s0f2u3i4\": \"NET\"\n },\n \"powerState\": \"ON\",\n \"primaryPort\": \"cdc-wdm0\",\n \"registrationStatus\": \"HOME\",\n \"serialNumber\": \"111111111111111\",\n \"signalQuality\": 55,\n \"signalStrength\": -80,\n \"simLocked\": true,\n \"softwareRevision\": \"EG25GGBR07A08M2G\",\n \"state\": \"ACTIVATED\",\n \"supportedBands\": [\n \"DCS\",\n \"EUTRAN_3\",\n \"EUTRAN_19\",\n \"EUTRAN_40\",\n \"EUTRAN_26\",\n \"EUTRAN_28\",\n \"EUTRAN_41\",\n \"UTRAN_6\",\n \"EUTRAN_13\",\n \"EUTRAN_25\",\n \"EUTRAN_5\",\n \"EUTRAN_7\",\n \"EUTRAN_8\",\n \"UTRAN_2\",\n \"EUTRAN_38\",\n \"UTRAN_1\",\n \"EUTRAN_12\",\n \"UTRAN_8\",\n \"EUTRAN_18\",\n \"UTRAN_19\",\n \"G850\",\n \"EUTRAN_20\",\n \"UTRAN_5\",\n \"EUTRAN_1\",\n \"EUTRAN_39\",\n \"EUTRAN_2\",\n \"EUTRAN_4\",\n \"EGSM\",\n \"PCS\",\n \"UTRAN_4\"\n ],\n \"supportedModemCapabilities\": [\n \"NONE\"\n ],\n \"supportedModes\": [\n {\n \"modes\": [\n \"MODE_4G\"\n ],\n \"preferredMode\": \"NONE\"\n },\n {\n \"modes\": [\n \"MODE_2G\",\n \"MODE_3G\",\n \"MODE_4G\"\n ],\n \"preferredMode\": \"MODE_4G\"\n }\n ],\n \"type\": \"MODEM\",\n \"virtual\": false\n}\n
"},{"location":"core-services/network-status-rest-v1/#networkinterfacestatus","title":"NetworkInterfaceStatus","text":"This object contains the common properties contained by the status object reported for a network interface. A network interface is identified by Kura using the id field. It is used to internally manage the interface. The interfaceName, instead, is the IP interface as it may appear on the system. For Ethernet and WiFi interfaces the two values coincide (i.e. eth0, wlp1s0, ...). For modems, instead, the id is typically the usb or pci path, while the interfaceName is the IP interface created when they are connected. When the modem is disconnected the interfaceName can have a different value.
Properties:
id: string
interfaceName: string
hardwareAddress: string
driver: string
driverVersion: string
firmwareVersion: string
virtual: bool
state: string (enumerated)
autoConnect: bool
mtu: number
interfaceIp4Addresses: array
(optional)
object
interfaceIp6Addresses: array
(optional)
object
Represents an IPv4 or IPv6 addresses as a string.
"},{"location":"core-services/network-status-rest-v1/#hardwareaddress","title":"HardwareAddress","text":"Represents an hardware address as its bytes reported as two characters hexadecimal strings separated by the ':' character. e.g. 00:11:22:33:A4:FC:BB.
"},{"location":"core-services/network-status-rest-v1/#networkinterfaceipaddress","title":"NetworkInterfaceIpAddress","text":"This object describes an IP address with its prefix. It can be used for IPv4 or IPv6 addresses.
Properties:
address: string
prefix: number
This class describes the IP address status of a network interface: a list of IP addresses, an optional gateway and a list of DNS servers address. It can be used for IPv4 or IPv6 addresses.
Properties:
addresses: array
object
gateway: string
(optional This field can be missing if the interface has no gateway.)
dnsServerAddresses: array
string
This class represent a WiFi channel, providing the channel number, frequency, status and other useful information.
Properties:
channel: number
frequency: number
disabled: bool
(optional)
attenuation: number
(optional)
noInitiatingRadiation: bool
(optional)
radarDetection: bool
(optional)
This object describes a Wifi Access Point. It can be used both for describing a detected AP after a WiFi scan when in Station mode and the provided AP when in Master (or Access Point) mode.
Properties:
ssid: string
The Service Set IDentifier of the WiFi network
hardwareAddress: string
channel: object
mode: string (enumerated)
maxBitrate: number
The maximum bitrate this access point is capable of.
signalQuality: number
The current signal quality of the access point in percentage.
signalStrength: number
The current signal strength of the access point in dBm.
wpaSecurity: array
The WPA capabilities of the access point
string (enumerated)
rsnSecurity: array
The RSN capabilities of the access point
string (enumerated)
This object represents a pair of Modem Mode list and a preferred one.
Properties:
modes: array
string (enumerated)
preferredMode: string (enumerated)
This class contains all relevant properties to describe a SIM (Subscriber Identity Module).
Properties:
active: bool
primary: bool
iccid: string
imsi: string
eid: string
operatorName: string
operatorIdentifier: string
simType: string (enumerated)
eSimStatus: string (enumerated)
This object describes the Bearer or Context associated to a modem connection.
Properties:
name: string
connected: bool
apn: string
ipTypes: array
string (enumerated)
bytesTransmitted: number
bytesReceived: number
An object representing a set of modem ports. The members of this object represent modem ports, the member names represent the modem port name. This object can have a variable number of members.
Properties:
string (enumerated)
The type of a network interface.
UNKNOWN
: The device type is unknownETHERNET
: The device is a wired Ethernet device.WIFI
: The device is an 802.11 WiFi device.UNUSED1
UNUSED2
BT
: The device is a Bluetooth device.OLPC_MESH
: The device is an OLPC mesh networking device.WIMAX
: The device is an 802.16e Mobile WiMAX device.MODEM
: The device is a modem supporting one or more of analog telephone, CDMA/EVDO, GSM/UMTS/HSPA, or LTE standards to access a cellular or wireline data network.INFINIBAND
: The device is an IP-capable InfiniBand interface.BOND
: The device is a bond master interface.VLAN
: The device is a VLAN interface.ADSL
: The device is an ADSL device.BRIDGE
: The device is a bridge master interface.GENERIC
: This is a generic support for unrecognized device types.TEAM
: The device is a team master interface.TUN
: The device is a TUN or TAP interface.TUNNEL
: The device is an IP tunnel interface.MACVLAN
: The device is a MACVLAN interface.VXLAN
: The device is a VXLAN interface.VETH
: The device is a VETH interface.MACSEC
: The device is a MACsec interface.DUMMY
: The device is a dummy interface.PPP
: The device is a PPP interface.OVS_INTERFACE
: The device is a Open vSwitch interface.OVS_PORT
: The device is a Open vSwitch portOVS_BRIDGE
: The device is a Open vSwitch bridge.WPAN
: The device is a IEEE 802.15.4 (WPAN) MAC Layer Device.SIXLOWPAN
: The device is a 6LoWPAN interface.WIREGUARD
: The device is a WireGuard interface. WIFI_P2P
: The device is an 802.11 Wi-Fi P2P device.VRF
: The device is a VRF (Virtual Routing and Forwarding) interface.LOOPBACK
: The device is a loopback device.The state of a network interface.
UNKNOWN
: The device is in an unknown state.UNMANAGED
: The device cannot be used (carrier off, rfkill, etc).UNAVAILABLE
: The device is not connected.DISCONNECTED
: The device is preparing to connect.PREPARE
: The device is being configured.CONFIG
: The device is awaiting secrets necessary to continue connection.NEED_AUTH
: The IP settings of the device are being requested and configured.IP_CONFIG
: The device's IP connectivity ability is being determined.IP_CHECK
: The device is waiting for secondary connections to be activated.SECONDARIES
: The device is waiting for secondary connections to be activated.ACTIVATED
: The device is active.DEACTIVATING
: The device's network connection is being turn down.FAILED
: The device is in a failure state following an attempt to activate it.The capability of a WiFi interface.
NONE
: The device has no encryption/authentication capabilitiesCIPHER_WEP40
: The device supports 40/64-bit WEP encryption.CIPHER_WEP104
: The device supports 104/128-bit WEP encryption.CIPHER_TKIP
: The device supports the TKIP encryption.CIPHER_CCMP
: The device supports the AES/CCMP encryption.WPA
: The device supports the WPA1 encryption/authentication protocol.RSN
: The device supports the WPA2/RSN encryption/authentication protocol.AP
: The device supports Access Point mode.ADHOC
: The device supports Ad-Hoc mode.FREQ_VALID
: The device reports frequency capabilities.FREQ_2GHZ
: The device supports 2.4GHz frequencies.FREQ_5GHZ
: The device supports 5GHz frequencies.MESH
: The device supports mesh points.IBSS_RSN
: The device supports WPA2 in IBSS networksModes of operation for wifi interfaces
UNKNOWN
: Mode is unknown.ADHOC
: Uncoordinated network without central infrastructure.INFRA
: Client mode - Coordinated network with one or more central controllers.MASTER
: Access Point Mode - Coordinated network with one or more central controllers.Flags describing the security capabilities of an access point.
NONE
: NonePAIR_WEP40
: Supports pairwise 40-bit WEP encryption.PAIR_WEP104
: Supports pairwise 104-bit WEP encryption.PAIR_TKIP
: Supports pairwise TKIP encryption.PAIR_CCMP
: Supports pairwise CCMP encryption.GROUP_WEP40
: Supports a group 40-bit WEP cipher.GROUP_WEP104
: Supports a group 104-bit WEP cipher.GROUP_TKIP
: Supports a group TKIP cipher.GROUP_CCMP
: Supports a group CCMP cipher.KEY_MGMT_PSK
: Supports PSK key management.KEY_MGMT_802_1X
: Supports 802.1x key management.SECURITY_NONE
: Supports no encryption.SECURITY_WEP
: Supports WEP encryption.SECURITY_WPA
: Supports WPA encryption.SECURITY_WPA2
: Supports WPA2 encryption.SECURITY_WPA_WPA2
: Supports WPA and WPA2 encryption.The type of a modem port.
UNKNOWN
NET
AT
QCDM
GPS
QMI
MBIM
AUDIO
IGNORED
The generic access technologies families supported by a modem.
NONE
: The modem has no capabilities.POTS
: The modem supports the Plain Old Telephone Service (analog wired telephone network).EVDO
: The modem supports EVDO revision 0, A or B.GSM_UMTS
: The modem supports at least one of GSM, GPRS, EDGE, UMTS, HSDPA, HSUPA or HSPA+ technologies.LTE
: The modem has LTE capabilities.IRIDIUM
: The modem supports Iridium technology.FIVE_GNR
: The modem supports 5GNR.TDS
: The modem supports TDS.ANY
: The modem supports all capabilities.The generic access mode a modem supports.
NONE
CS
MODE_2G
MODE_3G
MODE_4G
MODE_5G
ANY
The radio bands supported by a modem when connected to a mobile network.
UNKNOWN
EGSM
DCS
PCS
G850
UTRAN_1
UTRAN_3
UTRAN_4
UTRAN_6
UTRAN_5
UTRAN_8
UTRAN_9
UTRAN_2
UTRAN_7
G450
G480
G750
G380
G410
G710
G810
EUTRAN_1
EUTRAN_2
EUTRAN_3
EUTRAN_4
EUTRAN_5
EUTRAN_6
EUTRAN_7
EUTRAN_8
EUTRAN_9
EUTRAN_10
EUTRAN_11
EUTRAN_12
EUTRAN_13
EUTRAN_14
EUTRAN_17
EUTRAN_18
EUTRAN_19
EUTRAN_20
EUTRAN_21
EUTRAN_22
EUTRAN_23
EUTRAN_24
EUTRAN_25
EUTRAN_26
EUTRAN_27
EUTRAN_28
EUTRAN_29
EUTRAN_30
EUTRAN_31
EUTRAN_32
EUTRAN_33
EUTRAN_34
EUTRAN_35
EUTRAN_36
EUTRAN_37
EUTRAN_38
EUTRAN_39
EUTRAN_40
EUTRAN_41
EUTRAN_42
EUTRAN_43
EUTRAN_44
EUTRAN_45
EUTRAN_46
EUTRAN_47
EUTRAN_48
EUTRAN_49
EUTRAN_50
EUTRAN_51
EUTRAN_52
EUTRAN_53
EUTRAN_54
EUTRAN_55
EUTRAN_56
EUTRAN_57
EUTRAN_58
EUTRAN_59
EUTRAN_60
EUTRAN_61
EUTRAN_62
EUTRAN_63
EUTRAN_64
EUTRAN_65
EUTRAN_66
EUTRAN_67
EUTRAN_68
EUTRAN_69
EUTRAN_70
EUTRAN_71
EUTRAN_85
CDMA_BC0
CDMA_BC1
CDMA_BC2
CDMA_BC3
CDMA_BC4
CDMA_BC5
CDMA_BC6
CDMA_BC7
CDMA_BC8
CDMA_BC9
CDMA_BC10
CDMA_BC11
CDMA_BC12
CDMA_BC13
CDMA_BC14
CDMA_BC15
CDMA_BC16
CDMA_BC17
CDMA_BC18
CDMA_BC19
UTRAN_10
UTRAN_11
UTRAN_12
UTRAN_13
UTRAN_14
UTRAN_19
UTRAN_20
UTRAN_21
UTRAN_22
UTRAN_25
UTRAN_26
UTRAN_32
ANY
NGRAN_1
NGRAN_2
NGRAN_3
NGRAN_5
NGRAN_7
NGRAN_8
NGRAN_12
NGRAN_13
NGRAN_14
NGRAN_18
NGRAN_20
NGRAN_25
NGRAN_26
NGRAN_28
NGRAN_29
NGRAN_30
NGRAN_34
NGRAN_38
NGRAN_39
NGRAN_40
NGRAN_41
NGRAN_48
NGRAN_50
NGRAN_51
NGRAN_53
NGRAN_65
NGRAN_66
NGRAN_70
NGRAN_71
NGRAN_74
NGRAN_75
NGRAN_76
NGRAN_77
NGRAN_78
NGRAN_79
NGRAN_80
NGRAN_81
NGRAN_82
NGRAN_83
NGRAN_84
NGRAN_86
NGRAN_89
NGRAN_90
NGRAN_91
NGRAN_92
NGRAN_93
NGRAN_94
NGRAN_95
NGRAN_257
NGRAN_258
NGRAN_260
NGRAN_261
The SIM (Subscriber Identity Module) type.
UNKNOWN
PHYSICAL
ESIM
The status of an ESIM.
UNKNOWN
NO_PROFILES
WITH_PROFILES
The type of Bearer or Context associated to a modem connection.
NONE
IPV4
IPV6
IPV4V6
NON_IP
ANY
PPP
: Point to Point ProtocolDirectIP
: Direct IPThe status of a modem.
FAILED
: The modem is unavailableUNKNOWN
: The modem is in an unknown state.INITIALIZING
: The modem is being initialised.LOCKED
: The modem is locked.DISABLED
: The modem is disabled and powered off.DISABLING
: The modem is disabling.ENABLING
: The modem is enabling..ENABLED
: The modem is enabled but not registered to a network provider.SEARCHING
: The modem is searching for a network provider.REGISTERED
: The modem is registered to a network provider.DISCONNECTING
: The modem is disconnecting.CONNECTING
: The modem is connecting.CONNECTED
: The modem is connected.The specific technology types used when a modem is connected or registered to a network.
UNKNOWN
POTS
GSM
GSM_COMPACT
GPRS
EDGE
UMTS
HSDPA
HSUPA
HSPA
HSPA_PLUS
ONEXRTT
EVDO0
EVDOA
EVDOB
LTE
FIVEGNR
LTE_CAT_M
LTE_NB_IOT
ANY
The registration status of a modem when connected to a mobile network.
IDLE
HOME
SEARCHING
DENIED
UNKNOWN
ROAMING
HOME_SMS_ONLY
ROAMING_SMS_ONLY
EMERGENCY_ONLY
HOME_CSFB_NOT_PREFERRED
ROAMING_CSFB_NOT_PREFERRED
ATTACHED_RLOS
An object reporting a failure while retrieving the status of a specific network interface
Properties:
interfaceId: string
The identifier of the interface whose status cannot be retrieved.
reason: string
A message describing the reason of the failure.
An object reporting a failure message.
Properties:
string
A message describing the failure.The Nvidia\u2122 Triton Server is an open-source inference service software that enables the user to deploy trained AI models from any framework on GPU or CPU infrastructure. It supports all major frameworks like TensorFlow, TensorRT, PyTorch, ONNX Runtime, and even custom framework backend. With specific backends, it is also possible to run Python scripts, mainly for pre-and post-processing purposes, and exploit the DALI building block for optimized operations. For more detail about the Triton Server, please refer to the official website.
Kura provides three components for exposing the Triton Server service functionality which implement the inference engine APIs and provides methods for interacting with a local or remote Nvidia\u2122 Triton Server:
Before running Kura's Triton Server Service, you must install the Triton Inference Server. Here you can find the necessary steps for the available suggested installation methods.
"},{"location":"core-services/nvidia-triton-server-inference-engine/#native-triton-installation-on-jetson-devices","title":"Native Triton installation on Jetson devices","text":"A release of Triton for JetPack is provided in the tar file in the Triton Inference Server release notes. Full documentation is available here.
Installation steps:
bin
folder.tritonserver
executable to your path or symlinking the executable to /usr/local/bin
.Before you can use the Triton Docker image you must install Docker. If you plan on using a GPU for inference you must also install the NVIDIA Container Toolkit.
Pull the image using the following command.
$ docker pull nvcr.io/nvidia/tritonserver:<xx.yy>-py3\n
Where <xx.yy>
is the version of Triton that you want to pull.
The official docs mention the possibility to perform a native installation on supported platform by extracting the binaries from the Docker images. To do so you must install the necessary dependencies (some can be found in the Jetson runtime dependencies docs) on the system. For Triton to support NVIDIA GPUs you must install CUDA, cuBLAS and cuDNN referencing the support matrix.
Note
For Python models the libraries available to the Python model are the ones available for the user running the Triton server. Therefore you'll need to install the libraries through pip
for the kurad
user.
The Triton Inference Server serves models from one or more model repositories that are specified when the server is started. The model repository is the directory where you place the models that you want Triton to serve. Be sure to follow the instructions to setup the model repository directory.
Further information about an example Triton Server setup can be found in the official documentation.
"},{"location":"core-services/nvidia-triton-server-inference-engine/#triton-server-remote-service-component","title":"Triton Server Remote Service component","text":"The Kura Triton Server Remote Service component is the implementation of the inference engine APIs and provides methods for interacting with a remote (i.e. unmnanaged) Nvidia\u2122 Triton Server. As presented below, the component enables the user to communicate to an external server to load specific models. With this component the server lifecycle (startup, shutdown) won't be handled by Kura and it's the user responsibility to make it available to Kura for connecting.
The parameters used to configure the Triton Service are the following:
io.grpc.StatusRuntimeException: RESOURCE_EXHAUSTED: gRPC message exceeds maximum size 4194304\n
Note
Pay attention on the ports used for communicating with the Triton Server. The default ports are the 8000-8002, but these are tipically used by Kura for debug purposes.
"},{"location":"core-services/nvidia-triton-server-inference-engine/#triton-server-native-service-component","title":"Triton Server Native Service component","text":"The Kura Triton Server component is the implementation of the inference engine APIs and provides methods for interacting with a local native Nvidia\u2122 Triton Server. As presented below, the component enables the user to configure a local server running on the gateway and handles its lifecycle. This operating mode supports more features for interacting with the server like the AI Model Encryption.
Note
Requirement: tritonserver
executable needs to be available in the path to the kurad
user. Be sure to have a working Triton Server installation before configuring the local native Triton Server instance through Kura UI.
The parameters used to configure the Triton Service are the following:
Note
Pay attention on the ports used for communicating with the Triton Server. The default ports are the 8000-8002, but these are tipically used by Kura for debug purposes.
"},{"location":"core-services/nvidia-triton-server-inference-engine/#triton-server-container-service-component","title":"Triton Server Container Service component","text":"The Kura Triton Server component is the implementation of the inference engine APIs and provides methods for interacting with a local container running the Nvidia\u2122 Triton Server. As presented below, the component enables the user to configure a local server running on the gateway and handles its lifecycle. This operating mode supports more features for interacting with the server like the AI Model Encryption.
Note
Requirement: 1. Triton Server container image already installed on the device. For instructions refer to the installation section in this page. 2. Kura's Container Orchestration Service enabled.
The parameters used to configure the Triton Service are the following:
nvidia
corresponds to --runtime=nvidia
. Note: when using the Nvidia Container Runtime, leave the GPUs field empty. The GPUs available on the system will be accessible from the container by default./dev/video0
).Note
Pay attention on the ports used for communicating with the Triton Server. The default ports are the 8000-8002, but these are typically used by Kura for debug purposes.
"},{"location":"core-services/nvidia-triton-server-inference-engine/#triton-server-service-component-deprecated-since-520","title":"Triton Server Service component [deprecated since 5.2.0]","text":"The Kura Triton Server component is the implementation of the inference engine APIs and provides methods for interacting with a local or remote Nvidia\u2122 Triton Server. As presented below, the component enables the user to configure a local server running on the gateway or to communicate to an external server to load specific models.
The parameters used to configure the Triton Service are the following:
Note
Pay attention on the ports used for communicating with the Triton Server. The default ports are the 8000-8002, but these are tipically used by Kura for debug purposes.
"},{"location":"core-services/nvidia-triton-server-inference-engine/#configuration-for-a-local-native-triton-server-with-triton-server-service-component-deprecated-since-520","title":"Configuration for a local native Triton Server with Triton Server Service component [deprecated since 5.2.0]","text":"Note
Requirement: tritonserver
executable needs to be available in the path to the kurad
user. Be sure to have a working Triton Server installation before configuring the local native Triton Server instance through Kura UI.
When the Local Nvidia Triton Server option is set to true, a local instance of the Nvidia\u2122 Triton Server is started on the gateway. The following configuration is required:
The typical command used to start the Triton Server is like this:
tritonserver --model-repository=<model_repository_path> \\\n--backend-directory=<backend_repository_path> \\\n--backend-config=<backend_config> \\\n--http-port=<http_port> \\\n--grpc-port=<grpc_port> \\\n--metrics-port=<metrics_port> \\\n--model-control-mode=explicit \\\n--load-model=<model_name_1> \\\n--load-model=<model_name_2> \\\n...\n
"},{"location":"core-services/nvidia-triton-server-inference-engine/#configuration-for-a-local-triton-server-running-in-a-docker-container-with-triton-server-service-component-deprecated-since-520","title":"Configuration for a local Triton Server running in a Docker container with Triton Server Service component [deprecated since 5.2.0]","text":"If the Nvidia\u2122 Triton Server is running as a Docker container in the gateway, the following configuration is required:
In order to correctly load the models at runtime, configure the server with the --model-control-mode=explicit
option. The typical command used for running the docker container is as follows. Note the forward of the ports to not interfere with Kura.
docker run --rm \\\n-p4000:8000 \\\n-p4001:8001 \\\n-p4002:8002 \\\n--shm-size=150m \\\n-v path/to/models:/models \\\nnvcr.io/nvidia/tritonserver:[version] \\\ntritonserver --model-repository=/models --model-control-mode=explicit\n
"},{"location":"core-services/nvidia-triton-server-inference-engine/#configuration-for-a-remote-triton-server-with-triton-server-service-component-deprecated-since-520","title":"Configuration for a remote Triton Server with Triton Server Service component [deprecated since 5.2.0]","text":"When the Nvidia\u2122 Triton Server is running on a remote server, the following configuration is needed:
For ensuring inference integrity and providing copyright protection of deep-learning models on edge devices, Kura provides decryption capabilities for trained models to be served through the Triton Server.
"},{"location":"core-services/nvidia-triton-server-inference-engine/#how-it-works","title":"How it works","text":"Prerequisites: a deep-learning trained model (or more) exists with the corresponding necessary configuration for running on the Triton Server without encryption. A folder containing the required files (model, configuration etc) has been tested on a Triton Server.
Restrictions: if model encryption is used, the following restrictions apply:
Once the development of the deep-learning model is complete, the developer who wants to deploy the model on the edge device in a secure manner can proceed with encrypting the Triton model using the procedure detailed below. After encrypting the model he/she can transfer the file on the edge device using his/her preferred method.
Kura will keep the stored model protected at all times and have the model decrypted in runtime only for use by the Inference Server Runtime. As soon as the model is correctly loaded into memory the decrypted model will be removed from the filesystem.
As an additional security measure, the Model Repository containing the decrypted models will be stored in a temporary subfolder and will feature restrictive permission such that only Kura, the Inference Server and the root
user will be able to access it.
Given a trained model inside the folder tf_autoencoder_fp32
(for example) with the following layout (see the official documentation for details):
tf_autoencoder_fp32\n\u251c\u2500\u2500 1\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 model.savedmodel\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 assets\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 keras_metadata.pb\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 saved_model.pb\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 variables\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 variables.data-00000-of-00001\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 variables.index\n\u2514\u2500\u2500 config.pbtxt\n
Compress the model into a zip archive with the following command:
zip -vr tf_autoencoder_fp32.zip tf_autoencoder_fp32/\n
then encrypt it with the AES 256 algorithm using the following gpg
command:
gpg --armor --symmetric --cipher-algo AES256 tf_autoencoder_fp32.zip\n
The resulting archive tf_autoencoder_fp32.zip.asc
can be transferred to the Local Model Repository Path on the target machine and will be decrypted by Kura.
The PositionService provides the geographic position of the gateway if a GPS component is available and enabled.
When this service is enabled and provides a valid geographic position, this position is published in the gateway birth certificate with its location.
The GPS connection parameters must be defined in order to allow the service to receive the GPS frames. The PositionService supports direct access to gps device or the connection to that through gpsd.
For a device that is not connected to a GPS, it is possible to define a static position by entering latitude, longitude,, altitude and GNSS Type. In this case, the position, date and time information is returned by the PositionService as if it were an actual GPS position. This may be useful when a gateway is installed in a known place and does not move.
To use this service, select the PositionService option located in the Services area as shown in the screen capture below.
This service provides the following configuration parameters:
enabled - defines whether or not this service is enabled or disabled. (Required field.)
static - specifies true or false whether to use a static position instead of a GPS. (Required field.)
provider - species which position provider use, can be gpsd or serial.
gpsd.host - host where gpsd service deamon is running. (required only if gpsd provider is selected.)
gpsd.port - port where gpsd service is listening. (required only if gpsd provider is selected.)
latitude - provides the static latitude value in degrees.
longitude - provides the static longitude value in degrees.
altitude - provides the static altitude value in meters.
GNSS Type - provides the gnss system used to retrieve static information.
port - supplies the USB or serial port of the GPS device.
baudRate - supplies the baud rate of the GPS device.
bitsPerWord - sets the number of bits per word (databits) for the serial communication to the GPS device.
stopbits - sets the number of stop bits for the serial communication to the GPS device.
parity - sets the parity for the serial communication to the GPS device.
Kura provides a built-in REST Service based on the osgi-jax-rs-connector project.
By default, REST service providers register their services using the context path /services
. The REST service provides the BASIC Authentication support and HTTPS client certificate authentication support.
Starting from Kura 5.4.0, REST service provides built in session management support, the Session REST APIs can be used to establish a session. Using sessions is the recommended way for interacting with Kura REST APIs from a browser based application, for this use case it is also possible to disable the default session-less BASIC and certificate based authentication (see the Basic Authentication Enabled and Enable Certificate Authentication Whitout Session Management configuration parameters below).
REST API access is available on all HTTP ports defined in the HTTP/HTTPS Configuration section, unless access is restricted to dedicated ports using the corresponding configuration parameter (see below).
Certificate authentication support is only available on the HTTPS With Certificate Authentication Ports configured in HTTP/HTTPS Configuration section.
Kura Identity names and passwords can be used for BASIC Authentication. Certificate authentication follows the same rules as Gateway Administration Console Authentication.
Warning
If the forced password change feature for a given identity is enabled, REST API password authentication will be blocked for that identity until the password is updated by the user or the feature is manually disabled. Certificate authentication will continue to be allowed even if the forced password change feature is enabled.
JAX-RS roles are mapped to Kura permissions, the name of a permission associated with a JAX-RS role is the rest. prefix followed by the role name. For example the assets role is mapped to the rest.assets permission. REST related permissions can be assigned to an identity using the Gateway Administration Console in the Identities section.
"},{"location":"core-services/rest-service/#rest-service-configuration","title":"Rest Service configuration","text":"The available configuration parameters are the following:
Allowed Ports: If set to a non empty list, REST API access will be allowed only on the specified ports. If set to an empty list, access will be allowed on all ports. Please make sure that the allowed ports are open in HttpService and Firewall configuration. (Default: empty)
Password Authentication Enabled: Enables or disables the built-in password authentication support. (Default: true)
Certificate Authentication Enabled: Enables or disables the built-in certificate authentication support. (Default: true)
Session Based Authentication Enabled: If set to true, enables authentication using the dedicated /services/session/v1
endpoints and cookie based session management. (Default: true)
Session Inactivity Interval (Seconds): The session inactivity interval, sessions will expire if no request is performed for the amount of time specified by this parameter in seconds. This parameter is ignored if Session Based Authentication Enabled is set to false. (Default: 900)
Basic Authentication Enabled: Allows to perform authentication by providing identity name and password as BASIC credentials in the request to any resource endpoint. Requires that the Password Authentication Enabled parameter is set to true. (Default: true)
Enable Certificate Authentication Without Session Management: If set to true, calling /services/session/v1/certificate
to create a session will not be necessary in order to perform certificate based authentication. Presenting a valid HTTPS client certificate and accessing resource endpoint directly is enough for authentication to succeed. Requires that the Certificate Authentication Enabled parameter is set to true. (Default: true)
Starting from Kura 5.2.0 it is also possible to develop custom REST authentication method providers by registering an implementation of the org.eclipse.kura.rest.auth.AuthenticationProvider
interface as an OSGi service. The org.eclipse.kura.example.rest.authentication.provider
bundle in Kura repository provides an example on how to implement a custom authentication method.
Kura exposes REST APIs for the Asset instances instantiated in the framework. Assets REST APIs are available in the context path /services/assets
. Following, the supported REST endpoints.
/
assets JSON None Returns the list of available assets GET /{pid}
assets JSON None Returns the list of available channels for the selected asset (specified by the corresponding PID) GET /{pid}/_read
assets JSON None Returns the read for all the READ channels in the selected Asset POST /{pid}/_read
assets JSON The list of channels where the READ operation should be performed. Returns the result of the read operation for the specified channels POST /{pid}/_write
assets JSON The list of channels and associated values that will be used for the WRITE operation. Performs the write operation for the specified channels returning the result of the operation."},{"location":"core-services/simple-artemis-mqtt-broker/","title":"Simple Artemis MQTT Broker","text":"By default, this instance is disabled but, selecting the Simple Artemis MQTT Broker option in Services it is possible to enable a basic instance of an \u200bActiveMQ-7 broker with MQTT capabilities.
The service has the following configuration fields:
Starting from version 5.3, Kura provides provides an integration of the SQLite database, based on the org.xerial:sqlite-jdbc wrapper .
The database integration is not included in the official distribution, but it can be downloaded from Eclipse Marketplace as a deployment package.
Warning
Note about Raspberry PI: Recent versions of Raspberry Pi OS 32 bit on Raspberry PI 4 will use by default a 64 bit kernel with a 32 bit userspace. This can cause issues to applications that use the result of uname -m
to decide which native libraries to load (see https://github.com/raspberrypi/firmware/issues/1795). This currently affects the Kura SQLite database connector. It should be possible to solve by switching to the 32 bit kernel setting arm_64bit=0
in /boot/config.txt
and restarting the device.
Kura supports the following SQLite database features:
Persistence modes: The implementation currently supports in-memory and file-based database instances.
Multiple database instances: It is possible to create and configure multiple database instances from the Kura Administration UI, these instances can be selectively consumed by applications.
Journaling modes: The implementation currently supports the WAL and rollback journal journaling modes.
Periodic database defrag and checkpoint: The implementations currently supports periodic defrag (VACUUM) and periodic WAL checkpoint.
To create a new SQLite database instance, use the following procedure:
org.eclipse.kura.db.SQLiteDbService
from the Factory drop-down list, enter an arbitrary name for the new instance and click Apply.The SQLite DB provides the following configuration parameters:
Database Mode: Defines the database mode. If In Memory
is selected, the database will not be persisted on the filesystem, all data will be lost if Kura is restarted and/or the database instance is deleted. If Persisted
is selected, the database will be stored on disk in the location specified by the Persisted Database Path parameter.
Persisted Database Path: Defines the path to the database file (it must include the database file name). This parameter is only relevant for persisted databases.
Encryption Key: Allows to specify a key/passphrase for encrypting the database file. This feature requires a SQLite binary with an encryption extension, and is only relevant for persisted databases. The key format can be specified using the Encryption Key Format parameter. If the value of this parameter is changed, the encryption key of the database will be updated accordingly. This parameter can be left empty to create an unencrypted database or to decrypt an encrypted one.
Note
The sqlite-jdbc version distributed with Kura does not contain any encryption extension, encryption features will not be available out of the box. See sqlite-jdbc documentaton for instructions about how to use a security extension.
Encryption Key Format: Allows to specify the format of the Encryption Key parameter value. The possible values are ASCII (an ASCII string), Hex SSE (the key is an hexadecimal string to be used with the SSE extension) or Hex SQLCipher (the key is an hexadecimal string to be used with the SQLCipher extension).
Journal Mode: The database journal mode. The following options are available:
Rollback Journal: The database instance will use the rollback journal for more details. More specifically, the DELETE argument will be passed to the pragma journal_mode command.
WAL: The database instance will use WAL mode. This is the default mode.
The WAL mode description page contains a comparison of the two modes.
Defrag enabled: Enables or disables the database defragmentation. Use the Defrag Interval parameter to specify the interval.
Defrag interval (seconds): The implementation supports running periodic defragmentation using the VACUUM command. This parameter specifies the interval in minutes between two successive checkpoints, set to zero to disable. This parameter is only relevant for persisted databases.
Warning
The total disk space used by SQLite database files might temporarily increase during defragmentation and/or if transactions that modify a lot of data are performed (including deletion). In particular:
It is recommended to perform some tests to determine the maximum database files size that will be used by the application and ensure that the size of the partition containing the database is at least twice as the expected db size.
WAL Checkpoint Interval (Seconds): The implementation supports running periodic periodic WAL checkpoints. Checkpoints will be performed in TRUNCATE mode. This parameter specifies the interval in seconds between two consecutive checkpoints, set to zero to disable. This parameter is only relevant for persisted databases in WAL Journal Mode. In WAL mode a checkpoint will be performed after a periodic defragmentation regardless of the value of this parameter.
Connection pool max size: The implementation manages connections using a connection pool. This parameter defines the maximum number of connections for the pool. If a new connection is requested
Delete Database Files On Failure: If set to true, the database files will be deleted in case of failure in opening a persisted database. This is intended as a last resort measure for keeping the database service operational, especially in the case when it is used as a cloud connection message store.
Debug Shell Access Enabled: Enables or disables the interaction with this database instance using the sqlitedbg:excuteQuery
OSGi console command. (see #debug-shell)
A database instance is identified by its Kura service PID. The PID for instances created using the Web UI is the string entered in the Name field at step 2 of the previous section.
The built-in components that use database functionalities allow to specify which instance to use in their configuration. These components are the DataService component of the cloud stack, the Wire Record Store and Wire Record Query wire components. The configuration of each component contains a property that allows to specify the Kura Service PID of the desired instance.
Warning
Using SQLite database instances through the deprecated DbFilter and DbStore components is not supported.
"},{"location":"core-services/sqlite-db-service/#usage-through-wires","title":"Usage through Wires","text":"It is possible to store and extract Wire Records into/from a SQLite database instance using the Wire Record Store and Wire Record Query wire components.
When a Wire Record is received by a Wire Record Store attached to a SQLite based database instance, the data will be stored in a table whose name is the current value of the Record Collection Name configuration parameter of the Wire Component.
Each property contained in a Wire Record will be appended to a column with the same name as the property key. A new column will be created if it doesn't already exists.
Since it is not possible to establish a one to one mapping between SQLite storage classes and the data types available on the Wires, the implementation will assign a custom type name to the created columns in order to keep track of the inserted Wire Record property type.
The custom types will be assigned according to the following table:
Wires Data Type Column Type Name Storage Class Type Affinity BOOLEAN BOOLEAN INTEGER INTEGER INT INTEGER LONG BIGINT INTEGER FLOAT FLOAT REAL DOUBLE DOUBLE REAL STRING TEXT TEXT BYTE_ARRAY BLOB BLOBThe custom column type makes it possible to preserve the original type when data is extracted with the Wire Record Query component. Please note that the resulting type may change in case of queries that build computed columns.
Warning
It is not recommended to store Wire Records having properties with the same key and different value type. If the value type changes, the target column will be dropped and recreated with the type derived from the last received record. All existing data in the target column will be lost. The purpose of this is to allow changing the type of a column with a Wire Graph configuration update.
"},{"location":"core-services/sqlite-db-service/#debug-shell","title":"Debug shell","text":"It is possible to inspect the contents of the database file using the OSGi console with the following command:
sqlitedbg:executeQuery dbServicePid 'query'\n
or more simply
executeQuery dbServicePid 'query'\n
where dbServicePid
is the user defined pid of the target database instance and query
is an arbitrary SQL query to be executed (make sure to properly quote the query string with the '
character). The command will print the result set or changed row count on the console.
It is only possible to access database instances whose Debug Shell Access Enabled configuration parameter is set to true
. The default of this parameter is false
.
The OSGi console is disabled by default, it can be accessed by starting the framework with the /opt/eclipse/kura/bin/start_kura_debug.sh
script and running the following command on the gateway:
telnet localhost 5002\n
Warning
This feature is intended for debug purposes only, the Debug Shell Access Enabled parameter as well as the OSGi console should not be left enabled on production systems.
"},{"location":"core-services/watchdog-service/","title":"Watchdog Service","text":"The WatchdogService provides methods for starting, stopping, and updating a hardware watchdog if it is present on the system. Once started, the watchdog must be updated to prevent the system from rebooting.
To use this service, select the WatchdogService option located in the Services area as shown in the screen capture below.
This service provides the following configuration parameters:
enabled - sets whether or not this service is enabled or disabled. (Required field)
pingInterval - defines the maximum time interval between two watchdogs' refresh to prevent the system from rebooting. (Required field)
Watchdog device path - sets the watchdog device path. (Required field)
Reboot Cause File Path - sets the path to the file that will contain the reboot cause information. (Required field)
Kura 5 introduces a centralized authentication and authorization framework based on the OSGi UserAdmin specification. This framework introduces the concepts of identities and permissions:
Identity: A Kura identity is related to authentication, an identity has a name and a set of associated credentials, for example a password.
Permission: A Kura permission is related to authorization. Zero or more permissions can be assigned to a given identity. Each permission allows to access a set of resources and/or perform certain operations. Permissions can be defined by applications.
Examples of applications that use the new authentication and authorization framework are the Web Console and the REST API framework:
ConfigurationService
based user and role definition mechanism has been dropped.The authentication and authorization framework only allows to define and store identities and permissions, it does not provide implementation of authentication methods and/or session management. These aspects are left to applications.
"},{"location":"gateway-configuration/authentication-and-authorization/#permission-and-identity-representation","title":"Permission and identity representation","text":"Permissions and identities are implemented on top of the UserAdmin User and Group concepts. See OSGi UserAdmin specification for more details on the Role, User and Group concepts.
"},{"location":"gateway-configuration/authentication-and-authorization/#identityservice-java-apis","title":"IdentityService Java APIs","text":"Kura 5.5 introduces a new set of Java APIs that allow to manage Kura identities, the implementation is based on the UserAdmin conventions described in this page, and allows to manipulate Kura identities without interacting directly with the UserAdmin. Please refer to the Javadoc for more details.
The new APIs also provide the capability to implement and register IdentityConfigurationExtensions in the framework.
An IdentityConfigurationExtension can define additional custom configuration parameters for each identity. The custom configuration can be inspected and modified in the Identities section of Kura Web UI and using the identity/v2 rest APIs and MQTT request handler. The IdentityConfigurationExtension implementation can store the additional configuration in the way that is most suitable for the application, for example by adding custom UserAdmin properties or credentials.
"},{"location":"gateway-configuration/authentication-and-authorization/#identities","title":"Identities","text":"A Kura identity is represented as a UserAdmin User with the following properties:
The User name must be in the kura.user.${identity_name}
form where ${identity_name}
is a non empty string representing the identity name. The name of an User representing a Kura identity must start with the kura.user.
prefix.
A password may be assigned to an identity by defining a property in User credentials with the following format:
kura.password
String org.eclipse.kura.crypto.CryptoService.sha256Hash(String)\n
method.Starting from Kura 5.1, it is possible to force an identity to change the password at next login by setting the following property in User properties: - kura.need.password.change
: true
encoded as a JSON string. - The property will be cleared automatically after a successful password change on next login.
Starting from Kura 5.5 the following restrictions will be applied by the IdentityService:
[A-Za-z0-9]+
) separated by the dot or underscore symbols, dot and underscore is not allowed at the beginning or at the end of the permission name, sequences of consecutive dots and/or underscores are not allowed (examples of valid names are foo1.bAr
, foo
, a.b.c
, foo.bar_baz
).A Kura permission is represented as a UserAdmin Group with the following properties:
The Group name must be in the kura.permission.${permission_name}
form where ${permission_name}
is a non empty string representing the permission name. The name of a Group representing a Kura permission must start with the kura.permission.
prefix.
Assigning a permission to a specific identity can be done by adding the User representing the identity to the basic members of the Group representing the permission.
Starting from Kura 5.5 the following restrictions will be applied by the IdentityService to the name new permissions:
[A-Za-z0-9]+
) separated by the dot symbol, the dot is not allowed at the beginning or at the end of the permission name (examples of valid permission names are foo1.bAr
, foo
, a.b.c
).The org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl
Kura service allows to persist the UserAdmin state in Kura configuration snapshot, this includes the defined identities and permissions.
The following configuration properties are used to store the UserAdmin concepts in Json format:
Stores the UserAdmin Roles, plain Roles are non used for representing Kura identities and permissions. The value must be a JSON array of Role elements.
Stores the UserAdmin Users. The value must be a JSON array of User elements.
Stores the UserAdmin Groups. The value must be a JSON array of Group elements.
"},{"location":"gateway-configuration/authentication-and-authorization/#json-representation-details","title":"JSON representation details","text":"This section describes the JSON format used in org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl
configuration.
A value appearing in UserAdmin dictionaries like properties and credentials
type : variant
Variants:
a String property
string
array
, element description: a byte of the array encoded as an unsigned integernumber
Examples:
\"A string property\"\n
[1, 2, 3, 4, 5]\n
"},{"location":"gateway-configuration/authentication-and-authorization/#useradmindict","title":"UserAdminDict","text":"A UserAdmin property dictionary, there are no well known property names, property values must be of UserAdminDictValue type
object
Example:
{\n \"stringProperty\": \"A string property\",\n \"byteArrayProperty\": [1, 2, 3, 4, 5]\n}\n
"},{"location":"gateway-configuration/authentication-and-authorization/#role","title":"Role","text":"An object describing and UserAdmin Role
type : object
Properties:
name The role name
type : string
properties
An object describing and UserAdmin User
type : object
Properties:
name The role name
type : string
properties
optional If the dictionary is empty
credentials
Example:
{\n \"name\": \"kura.user.appadmin\",\n \"credentials\": {\n \"kura.password\": \"3hPckF8Zc+IF3pVineBvck3zJERUl8itosySULE1hpM=\"\n }\n}\n
"},{"location":"gateway-configuration/authentication-and-authorization/#group","title":"Group","text":"An object describing and UserAdmin Group
type : object
Properties:
name The role name
type : string
properties
optional If the dictionary is empty
credentials
optional If the dictionary is empty
basicMembers
optional If the list is empty The list of the group basic members
array
, element description: A role namestring
requiredMembers
array
, element description: A role namestring
Example:
{\n \"name\": \"kura.permission.kura.wires.admin\",\n \"basicMembers\": [\"kura.user.appadmin\"]\n}\n
"},{"location":"gateway-configuration/cellular-configuration/","title":"Cellular Configuration","text":"If it is not configured, the cellular interface is presented on the interface list either by modem USB address, or if serial modem is used, by modem name. This 'fake' interface name is replaced by 'proper' interface name (e.g., ppp0) when the first modem configuration is submitted.
The cellular interface should be configured by first enabling it in the TCP/IP tab, and then setting the Cellular tab. Note that the cellular interface can only be set as WAN using DHCP. The cellular interface configuration options are described below.
"},{"location":"gateway-configuration/cellular-configuration/#cellular-configuration_1","title":"Cellular Configuration","text":"The Cellular tab contains the following configuration parameters:
Model: specifies the modem model.
Network Technology: describes the network technology used by this modem.
Modem Identifier: provides a unique name for this modem.
Interface #: provides a unique number for the modem interface (e.g., an interface # of 0 would name the modem interface ppp0).
Dial String: instructs how the modem should attempt to connect. Typical dial strings are as follows:
APN: defines the modem access point name.
This parameter is mandatory for standard profiles and optional for generic ones. In the case of generic profiles, if it is left empty, the value is automatically picked up from the Mobile Broadband Provider the modem is registered to. If a value is filled, the APN value is explicitly configured.
To avoid misconfiguration issues, it is strongly recommended to set it manually.
Note
APN value configuration
A good practice is to set the interface status to Disabled and then Enable For WAN when the APN is explicitly set. NetworkManager, indeed, will fallback to the default value if a wrong APN is specified, causing misleading behaviors. This does not happen if the interface is disabled and re-enabled after APN changes.
Auth Type: specifies the authentication type.
Username: supplies the username; disabled if no authentication method is specified.
Password: supplies the password; disabled if no authentication method is specified.
Modem Reset Timeout: sets the modem reset timeout in minutes. If set to a non-zero value, the modem is reset after n consecutive minutes of unsuccessful connection attempts. If set to zero, the modem keeps trying to establish a PPP connection without resetting. The default value is 5 minutes.
Reopen Connection on Termination: sets the persist option of the PPP daemon that specifies if PPP daemon should exit after connection is terminated. Note that the maxfail option still has an effect on persistent connections.
Connection Attempts Retry Delay: Sets the holdoff parameter to instruct the PPP daemon on how many seconds to wait before re-initiating the link after it terminates. This option only has any effect if the persist option (Reopen Connection on Termination) is set to true. The holdoff period is not applied if the link was terminated because it was idle. The default value is 1 second.
Connection Attempts: sets the maxfail option of the PPP daemon that limits the number of consecutive failed PPP connection attempts. The default value is 5 connection attempts. A value of zero means no limit. The PPP daemon terminates after the specified number of failed PPP connection attempts and restarts by the ModemMonitor thread.
Disconnect if Idle: sets the idle option of the PPP daemon, which terminates the PPP connection if the link is idle for a specified number of seconds. The default value is 95 seconds. To disable this option, set it to zero.
Active Filter: sets the active-filter option of the PPP daemon. This option specifies a packet filter (filter-expression) to be applied to data packets in order to determine which packets are regarded as link activity, and thereby, reset the idle timer. The filter-expression syntax is as described for tcpdump(1); however, qualifiers that do not apply to a PPP link, such as ether and arp, are not permitted. The default value is inbound. To disable the active-filter option, leave it blank.
LCP Echo Interval: sets the lcp-echo-interval option of the PPP daemon. If set to a positive number, the modem sends LCP echo request to the peer at the specified number of seconds. To disable this option, set it to zero. This option may be used with the lcp-echo-failure option to detect that the peer is no longer connected.
LCP Echo Failure: sets the lcp-echo-failure option of the PPP daemon. If set to a positive number, the modem presumes the peer to be dead if a specified number of LCP echo-requests are sent without receiving a valid LCP echo-reply. To disable this option, set it to zero.
The GPS tab allows the user to enable or disable the GPS module provided by the cellular modem. The available properties are:
UNMANAGED
: the GPS device of the modem will be setup but not directly managed, therefore freeing the serial port for other services to use. This can be used in order to perform the setup of the GPS and then have another service (like gpsd
) parse the NMEA strings in order to extract the position informations.MANAGED_GPS
: the GPS device of the modem will be setup and directly managed (typically by ModemManager) therefore the serial port won't be available for other services to use.GPS modes availability
GPS modes available for the modem are dependent on the modem model, modem firmware version and ModemManager version installed on the system. Some modes may not be selectable if the modem does not support them.
For \"device-specific profiles\" the GPS mode is not available and implicitly set to UNMANAGED
.
Therefore, to use the GPS module provided by the cellular modem with Kura's PositionService, the following considerations should be taken into account:
gpsd
and serial
PositionService providers with the GPS module provided by the cellular modem, the GPS mode should be set to UNMANAGED
.modemmanager
PositionService provider with the GPS module provided by the cellular modem, the GPS mode should be set to MANAGED_GPS
.Refer to the Position Service section for more information.
"},{"location":"gateway-configuration/cellular-configuration/#cellular-linux-configuration","title":"Cellular Linux Configuration","text":"This section describes the changes applied by Kura at the Linux networking configuration. Please read the following note before proceeding with manual changes of the Linux networking configuration.
Warning
It is NOT recommended performing manual editing of the Linux networking configuration files when the gateway configuration is being managed through Kura. While Linux may correctly accept manual changes, Kura may not be able to interpret the new configuration resulting in an inconsistent state.
When the cellular configuration is submitted, Kura generates peer and chat scripts used by the PPP daemon to establish a PPP connection. Examples of these scripts for HSPA and EVDO modems are shown below.
"},{"location":"gateway-configuration/cellular-configuration/#example-peer-script-for-hspa-modem","title":"Example Peer Script for HSPA Modem","text":"921600\nunit 0\nlogfile /var/log/HE910-D_2-1.5\ndebug\nconnect 'chat:v:f /etc/ppp/scripts/chat_HE910-D_2-1.5'\ndisconnect 'chat:v:f /etc/ppp/scripts/disconnect_HE910-D_2-1.5'\nmodem\nlock\nnoauth\nnoipdefault\ndefaultroute\nusepeerdns\nnoproxyarp\nnovj\nnovjccomp\nnobsdcomp\nnodeflate\nnomagic\nidle 95\nactive-filter 'inbound'\npersist\nholdoff 1\nmaxfail 5\nconnect-delay 1000\n
"},{"location":"gateway-configuration/cellular-configuration/#example-chat-script-for-hspa-modem","title":"Example Chat Script for HSPA Modem","text":"ABORT \"BUSY\"\nABORT \"VOICE\"\nABORT \"NO CARRIER\"\nABORT \"NO DIALTONE\"\nABORT \"NO DIAL TONE\"\nABORT \"ERROR\"\n\"\" \"+++ath\"\nOK \"AT\"\nOK AT+CGDCONT=1,\"IP\",\"c1.korem2m.com\"\nOK \"\\d\\d\\d\"\n\"\" \"atd-99---1#\"\nCONNECT \"\\c\"\n
"},{"location":"gateway-configuration/cellular-configuration/#example-peer-script-for-evdo-modem","title":"Example Peer Script for EVDO Modem","text":"921600\nunit 0\nlogfile /var/log/DE910-DUAL_1-1.5\ndebug\nconnect 'chat:v:f /etc/ppp/scripts/chat_DE910-DUAL_1-1.5'\ndisconnect 'chat:v:f /etc/ppp/scripts/disconnect_DE910-DUAL_1-1.5'\ncrtscts\nlock\nnoauth\ndefaultroute\nusepeerdns\nidle 95\nactive-filter 'inbound'\npersist\nholdoff 1\nmaxfail 5\nconnect-delay 10000\n
"},{"location":"gateway-configuration/cellular-configuration/#example-chat-script-for-evdo-modem","title":"Example Chat Script for EVDO Modem","text":"ABORT \"BUSY\"\nABORT \"VOICE\"\nABORT \"NO CARRIER\"\nABORT \"NO DIALTONE\"\nABORT \"NO DIAL TONE\"\nABORT \"ERROR\"\n\"\" \"+++ath\"\nOK \"AT\"\nOK \"ATE1V1&F&D2&C1&C2S0=0\"\nOK \"ATE1V1\"\nOK \"ATS7=60\"\nOK \"\\d\\d\\d\"\n\"\" \"atd#777\"\nCONNECT \"\\c\"\n
"},{"location":"gateway-configuration/cloud-connections/","title":"Cloud Connections","text":"The Cloud Connections section of the Kura Gateway Administration Console allows to create and manage cloud connections.
By default, Kura starts with a single cloud connection, as depicted in the following image:
The cloud services page allows to: - create a new cloud connection; - delete an existing cloud connection; - connect a selected cloud stack to the configured cloud platform; - disconnect the selected cloud stack from the connected cloud platform; - refresh the existing cloud connections.
When clicking on the New button, a dialog is displayed as depicted in the image below:
The user can select one of the existing cloud connection factories and give it a name (depending on the implementation, a name format can be suggested or forced).
Selecting a created Cloud Connection it is possible to associate a new publisher/subscriber by clicking the New Pub/Sub button. As for the connection creation case, the user can select one of the existing publisher/subscriber factories and give it a name.
"},{"location":"gateway-configuration/cloud-service-configuration/","title":"Cloud Service Configuration","text":"The CloudService provides an easy-to-use API layer for the M2M application to communicate with a remote server. It operates as a decorator for the DataService, providing add-on features over the management of the DataTransport layer.
In addition to simple publish/subscribe, the Cloud Connection API simplifies the implementation of more complex interaction flows like request/response or remote resource management. The Cloud Connection abstracts the developers from the complexity of the transport protocol and payload format used in the communication.
The Cloud Connection allows a single connection to a remote server to be shared across more than one application in the gateway, providing the necessary topic partitioning. Its functions include:
Adds application topic prefixes to allow a single remote server connection to be shared across applications.
Defines a payload data model and provides default encoding/decoding serializers.
Publishes life-cycle messages when the device and applications start and stop.
To use this service, select the CloudService option located in the Cloud Services area as shown in the screen capture below.
The CloudService provides the following configuration parameters:
device.display-name: defines the device display name given by the system. (Required field).
device.custom-name: defines the custom device display name if the device.display-name parameter is set to \"Custom\".
topic.control-prefix: defines the topic prefix used for system and device management messages.
encode.gzip: defines if the message payloads are sent compressed.
republish.mqtt.birth.cert.on.gps.lock: when set to true, forces a republish of the MQTT Birth Certificate when a GPS correct position lock is received. The device is then registered with its real coordinates. (Required field).
republish.mqtt.birth.cert.on.modem.detect: when set to true, forces a republish of the MQTT Birth Certificate when the service receives a modem detection event. This functionality is currently not supported on devices configured to use NetworkManager, in this case the property value is ignored. (Required field).
enable.default.subscriptions: manages the default subscriptions to the gateway management MQTT topics. When disabled, the gateway will not be remotely manageable.
payload.encoding: specifies the encoding for the messages sent by the specific CloudService instance.
{\n\"sentOn\" : 1491298822,\n\"position\" : {\n \"latitude\" : 45.234,\n \"longitude\" : -7.3456,\n \"altitude\" : 1.0,\n \"heading\" : 5.4,\n \"precision\" : 0.1,\n \"speed\" : 23.5,\n \"timestamp\" : 1191292288,\n \"satellites\" : 3,\n \"status\" : 2\n},\n\"metrics\": {\n \"code\" : \"A23D44567Q\",\n \"distance\" : 0.26456E+4,\n \"temperature\" : 27.5,\n \"count\" : 12354,\n \"timestamp\" : 23412334545,\n \"enable\" : true,\n \"rawBuffer\" : \"cGlwcG8gcGx1dG8gcGFwZXJpbm8=\"\n},\n\"body\": \"UGlwcG8sIHBsdXRvLCBwYXBlcmlubywgcXVpLCBxdW8gZSBxdWEu\"\n}\n
The default CloudService implementations publishes the following lifecycle messages:
The DataService provides the ability to connect to a remote broker, publish messages, subscribe to topics, receive messages on the subscribed topics, and disconnect from the remote message broker. The DataService delegates to the MqttDataTransport service the implementation of the transport protocol that is used to interact with the remote server.
The DataService also adds the capability of storing published messages in a persistent store function and sending them over the wire at a later time. The purpose of this feature is to relieve service users from implementing their own persistent store. Service users may publish messages independently on the DataService connection status.
Info
Starting from Kura 5.3.0, the DataService allows to bind to custom persistent stores. A custom persistent store can be defined by creating an implementation the new org.eclipse.kura.message.store.provider.MessageStoreProvider
service interface and registering it as an OSGi service.
In order to overcome the potential latencies introduced by buffering messages, the DataService allows a priority level to be assigned to\u200b each published message. Depending on the store configuration, there are certain guarantees that stored messages are not lost due to sudden crashes or power outages.
To use this service, select the DataService option located in the Cloud Connections area as shown in the screen capture below.
The DataService offers methods and configuration options to manage the connection to the remote server including the following (all required) parameters described below.
org.eclipse.kura.message.store.provider.MessageStoreProvider
interface.The DataService offers methods and configuration options to monitor the connection to the remote server and, eventually, cause a system reboot to recover from transient network problems.
This feature, if enabled, leverages the watchdog service and reboots the gateway if the maximum number of configured connection attempts has been made.
A reboot is not requested if the connection to the remote broker succeeds but an authentication error, an invalid client id or an authorization error is thrown by the remote cloud platform and causes a connection drop.
The image below shows the parameters that need to be tuned in order to enable this connection monitor feature.
To configure this functionality, the System Administrator needs to specify the following configuration elements:
Enable Recovery On Connection Failure: when enabled, activates the recovery feature on connection failure: if the device is not able to connect to a remote cloud platform, the service will wait for a specified amount of connection retries. If the recovery fails, the device will be rebooted. Being based on the Watchdog service, it needs to be activated as well.
Connection Recovery Max Failure: related to the previous parameter. It specifies the number of failures before a reboot is requested. !!! warning To be fully working, this feature needs the enabling of the Watchdog Service.
In order to have a finer control on the data flow, when a device reconnects to a remote cloud platform, Kura integrates into the Data Service a Backoff delay feature that limits the rate of messages sent.
This feature, enabled by default, integrates the Token Bucket concept to limit the bursts of messages sent to a remote cloud platform.
In the image below, the parameters that need to be tuned, in the Data Service, to take advantage of this feature:
Rate Limit Average - he average message publish rate in number of messages per unit of time (e.g. 10 messages per MINUTE).
Danger
The maximum allowed message rate is 1 message per millisecond, so the following limitations are applied:
The default setup limits the data flow to 1 message per second with a bucket size of 1 token.
Warning
This feature needs to be properly tuned by the System Administrator in order to prevent delays in the remote cloud platform due to messages stacked at the edge.
If not sure of the number of messages that your gateways will try to push to the remote platform, we suggest to disable this feature.
"},{"location":"gateway-configuration/data-service-configuration/#connection-schedule","title":"Connection schedule","text":"Starting from Kura 5.3.0, the Data Service supports a configurable time based connection schedule. If this functionality is enabled, the Data Service will connect at specific time instants represented by a configurable Cron expression, keep the connection open until it becomes idle and then disconnect until the next instant that matches the expression.
More in detail, the connection logic is as follows:
The DataService parses the confgiured Cron expression and schedules a connection attempt at the next instant that matches the expression. When the connection instant is reached, the logic continues from step 2.
The Data Service will start the auto connect logic. One or more connection attempts will be performed until the connection is established honoring the connect.retry-interval parameter.
The Data Service starts a timer that ticks after connection.schedule.inactivity.interval.seconds seconds. When the timer ticks the connection will be closed, and the logic resumed from step 1. The timer is reset delaying the disconnection when a message is published or confirmed (for QoS >= 1). The connection will not be closed if there are messages with QoS >= 1 that have not been confirmed yet. If an unexpected connection drop occurs in this phase, the logic will resume from step 2.
The Data Service will attempt to detect large time shifts in system clock, if a time shift is detected, the logic will switch to step 1, rescheduling the next connection attempt.
The relevant configuration parameters are the following:
Enable Connection Schedule: Enables or disables the connection schedule feature. Please note that in order to enable the connection logic, the Connect Auto-on-startup parameter must be set to true as well.
Connection Schedule CRON Expression: A CRON expression that specifies the instants when the gateway should perform a connection attempt. This parameter is only used if Enable Connection Schedule is set to true. The default expression schedules a connection every day at midnight.
Allow priority message to overide connection schedule - Allows messages beyond a specified priority to force a connection and be sent regardless of connection schedule.
Message schedule priority override threshold - A message with a priority equal to or less than this threshold will cause the framework to automatically re-connect and send regardless of the connection schedule.
Connection Schedule Disconnect Inactivity Interval Second: Specifies an inactivity timeout in seconds. If the timeout expires, the cloud connection will be automatically closed. This parameter is only used if Enable Connection Schedule is set to true.
Starting from Kura 5.3.0, the DataService allows to limit the maximum payload size for published messages. Attempts to publish a payload larger than the configured threshold will fail with a KuraStoreException. The threshold can be configured with the following parameter:
In order to keep backwards compatibility, the default value for the parameter is set to 16777216 bytes, which is the maximum allowed size by the current H2DbService implementation.
"},{"location":"gateway-configuration/data-transport-service-configuration/","title":"Data Transport Service Configuration","text":"The DataTransport service provides the ability to connect to a remote broker, publish messages, subscribe to topics, receive messages on the subscribed topics, and disconnect from the remote message broker. To use this service, select the MqttDataTransport option located in the Cloud Connections area as shown in the screen captures below.
The MqttDataTransport service provides the following configuration parameters:
broker-url: defines the URL of the MQTT broker to connect to. For the Everyware Cloud sandbox, this address is either mqtt://broker-sbx.everyware.io:1883/ or mqtts://broker-sbx.everyware.io:8883/ for an encrypted connection. (Required field).
topic.context.account-name: defines the name of the account to which the device belongs.
username and password: define the username and password that have been assigned to the device by the account administrator (generally username is account-name_broker). (Required field).
client-id: defines the identifier of the MQTT client representing the device when connecting to the MQTT broker. If left empty, it is automatically determined by the client software as the MAC address of the main network interface (in general numbers and uppercase letters without ':'). This identifier has to be unique within your account.
keep-alive: defines the \"keep alive\" interval measured in seconds. It specifies the maximum amount of time that should pass without communication between the client and the server. The client will ensure that at least one message travels across the network within each keep alive period. In the absence of a data-related message during this time period, the client will send a very small MQTT \"ping\" message that the server will acknowledge. The keep alive interval enables the client to detect when the server is no longer available without having to wait for the long TCP/IP timeout. (Required field).
Warning
The keep-alive interval may \"conflict\" with the TCP idle timeout set at the TCP/IP level. As a best practice the TCP idle timeout should be at least 1,5 times the keep-alive time interval. If the TCP idle timeout is less or equal the keep-alive, the MQTT connection may be dropped due to the TCP idle timeout expiration.
timeout: sets the timeout used for all interactions with the MQTT broker. (Required field).
clean-session: controls the behavior of both the client and the server at the time of connection and disconnection. When this parameter is set to true, the state information is discarded at connection and disconnection; when set to false, the state information is maintained. (Required field).
lwt parameters: define the MQTT \"Last Will and Testament\" (LWT) settings for the client. In the event that the client unexpectedly loses its connection to the server, the server publishes the LWT message (lwt.payload) to the LWT topic on behalf of the client. This allows other clients (subscribed to the LWT topic) to be made aware that the client has disconnected. LWT parameters that may be configured include:
in-flight.persistence: defines the storage type where in-flight messages are persisted across reconnections. They may be stored in memory, or in a file on the disk. (Required field).
protocol-version: defines the MQTT Protocol version to be used. This value may be 3.1 or 3.1.1.
SSL parameters: define the SSL specific settings for the client. SSL parameters that can be configured include:
The Device section provides several information about the gateway where Kura is running on. This section can be accessed by selecting the Device option located in the System area.
"},{"location":"gateway-configuration/device-information/#profile","title":"Profile","text":"The Profile tab shows several information about the gateway, organized under the Device, Hardware, Software and Java Information.
"},{"location":"gateway-configuration/device-information/#bundles","title":"Bundles","text":"This tab lists all the bundles installed on Kura, with details about the name, version, id, state and signature status. The signature value will be true if the corresponding bundle is signed, false otherwise.
The buttons in the upper part of the tab allows the user to manage the listed bundles:
The Containers tab lists the containers and images that are currently managed by the Container Orchestration Service. From this tab, the user can start and stop containers and delete images.
"},{"location":"gateway-configuration/device-information/#threads","title":"Threads","text":"The Threads tab shows a list of the threads that are currently running in the JVM.
"},{"location":"gateway-configuration/device-information/#system-packages","title":"System Packages","text":"The System Packages tab shows the list of all the Linux packages installed on the OS. The package is detailed with the name, version and type (DEB/RPM/APK).
"},{"location":"gateway-configuration/device-information/#system-properties","title":"System Properties","text":"The System Properties tab shows a list of relevant properties including OS and JVM parameters.
"},{"location":"gateway-configuration/device-information/#command","title":"Command","text":"A detailed description of this tab is presented in the Command Service page.
"},{"location":"gateway-configuration/device-information/#system-logs","title":"System Logs","text":"The System Logs tab allows downloading a compressed file containing all the relevant log files from the gateway. The download button creates and downloads a compressed file with the following items:
/var/log
or the content of the folder defined by the kura.log.download.sources property;kura-journal.log
);system-journal.log
).In addition to this feature, the page also allows the real-time displaying of system logs, if the framework has the availability of one or more components that implement the LogProvider API. The UI also provides a useful button to open a new Kura instance in a new browser window. A reference implementation of the LogProvider API is provided in the org.eclipse.kura.log.filesystem.provider
bundle. This bundle exposes in the framework a factory that can be used to read filesystem files. By default, Eclipse Kura creates two log providers at startup: one that reads from /var/log/kura.log
and the other that reads from /var/log/kura-audit.log
.
The collected logs are stored in a cache server-side and are collected from the point in time where the log providers get attached to the UI (usually, from the login or after a refresh of the browser's window). When the section \"System Logs\" is accessed, the new log entries are polled from the server's cache and stored client-side.
"},{"location":"gateway-configuration/ethernet-configuration/","title":"Ethernet Configuration","text":"As described in the Network Configuration section, Ethernet interfaces have two configuration tabs: TCP/IP and DHCP & NAT. Each Ethernet interface may be configured either as LAN or WAN; it may also be disabled.
If the interface is designated as LAN and is manually configured, the DHCP & NAT tab is enabled to allow DHCP server and/or 'many-to-one' NAT setup; otherwise, the DHCP & NAT tab is disabled.
For more information on TCP/IP and DHCP & NAT settings, please refer to the Network Configuration section.
"},{"location":"gateway-configuration/firewall-configuration/","title":"Firewall Configuration","text":"Kura offers easy management of the Linux firewall iptables and ip6tables included in an IoT Gateway. Additionally, Kura provides the ability to manage network access security to an IoT Gateway for both IPv4 and IPv6 through the following:
Open Ports, Port Forwarding, and IP Forwarding and Masquerading are configured via respective Firewall configuration tabs. 'Automatic' NAT is enabled for each local (LAN) interface using the DHCP & NAT tab of the respective interface configuration. While the IPv4 Firewall configuration capability is present on all IoT Gateways, the IPv6 Firewall is present only on devices that support IPv6 Networking.
"},{"location":"gateway-configuration/firewall-configuration/#firewall-linux-configuration","title":"Firewall Linux Configuration","text":"This section describes the changes applied by Kura at the Linux networking configuration. Please read the following note before proceeding with manual changes of the Linux networking configuration.
Warning
It is NOT recommended performing manual editing of the Linux networking configuration files when the gateway configuration is being managed through Kura. While Linux may correctly accept manual changes, Kura may not be able to interpret the new configuration resulting in an inconsistent state.
When a new firewall configuration is submitted, Kura immediately applies it using the iptables service provided by the OS. Moreover, the rules are stored in the filesystem and a new Kura snapshot is generated containing the new configuration. At the next startup, the firewall service in the OS will re-apply them and Kura will check the firewall configuration against the one contained in the last snapshot. In this way, the user can update the snapshot with the needed rules and apply them to the system using the webUI or modify the snapshot_0.xml
before the first start of Kura.
In order to allow a better coexistence between Kura and external applications that need to modify firewall rules, Kura writes its rules to a set of custom iptables chains. They are input-kura, output-kura, forward-kura, forward-kura-pf and forward-kura-ipf for the filter table and input-kura, output-kura, prerouting-kura, prerouting-kura-pf, postrouting-kura, postrouting-kura-pf and postrouting-kura-ipf for the nat table. The custom chains are then put in their respective standard iptables chains, as shown in the following:
iptables -t filter -I INPUT -j input-kura\niptables -t filter -I OUTPUT -j output-kura\niptables -t filter -I FORWARD -j forward-kura\niptables -t filter -I forward-kura -j forward-kura-pf\niptables -t filter -I forward-kura -j forward-kura-ipf\niptables -t nat -I PREROUTING -j prerouting-kura\niptables -t nat -I prerouting-kura -j prerouting-kura-pf\niptables -t nat -I INPUT -j input-kura\niptables -t nat -I OUTPUT -j output-kura\niptables -t nat -I POSTROUTING -j postrouting-kura\niptables -t nat -I postrouting-kura -j postrouting-kura-pf\niptables -t nat -I postrouting-kura -j postrouting-kura-ipf\n
The same custom chains are used in the IPv6 case.
Even if many firewall rules can be handled by Kura, it could be that some rules cannot be filled through the Web Console. In this case, custom firewall rules may be added to the /etc/init.d/firewall_cust script manually. These rules are applied/reapplied every time the firewall service starts, that is at the gateway startup. These custom rules should not be applied to the Kura custom chains, but to the standard ones.
"},{"location":"gateway-configuration/firewall-configuration/#open-ports","title":"Open Ports","text":"If Kura is running on a gateway, all TCP/UDP ports are closed by default unless they are listed in the Open Ports IPv4 or Open Ports IPv6 tab of the Firewall section in the Gateway Administration Console, or in the /etc/sysconfig/iptables
script. Therefore, if a user needs to connect to a specific port on a gateway, it is insufficient to have an application listening on the desired port; the port also needs to be opened in the firewall.
To open a port using the Gateway Administration Console, select the Firewall option located in the System area. The Firewall configuration display appears in the main window. With the Open Ports IPv4 or Open Ports IPV6 tab selected, click the New button. The New Open Port Entry form appears.
The New Open Port Entry form contains the following configuration parameters:
Complete the New Open Port Entry form and click the Submit button when finished. Once the form is submitted, a new port entry will appear. Click the Apply button for the change to take effect.
The firewall rules related to the open ports section are stored in the input-kura custom chain of the IPv4/IPv6 filter table.
"},{"location":"gateway-configuration/firewall-configuration/#port-forwarding","title":"Port Forwarding","text":"Port forwarding rules are needed to establish connectivity from the WAN side to a specific port on a host that resides on a LAN behind the gateway. In this case, a routing solution may be avoided since the connection is made to a specified external port on a gateway, and packets are forwarded to an internal port on the destination host; therefore, it is not necessary to add the external port to the list of open ports.
To add a port forwarding rule, select the Port Forwarding IPv4 or Port Forwarding IPv6 tab on the Firewall display and click the New button. The Port Forward Entry form appears.
The Port Forward Entry form contains the following configuration parameters:
Input Interface: specifies the interface through which a packet is going to be received. (Required field).
Output Interface: specifies the interface through which a packet is going to be forwarded to its destination. (Required field).
LAN Address: supplies the IP address of destination host. (Required field).
Protocol: defines the protocol (tcp or udp). (Required field).
External Port: provides the external destination port on gateway unit. (Required field).
Internal Port: provides the port on a destination host. (Required field).
Enable Masquerading: defines whether masquerading is used (yes or no). If enabled, the gateway replaces the IP address of the originating host with the IP address of its own output (LAN) interface. This is needed when the destination host does not have a back route to the originating host (or default gateway route) via the gateway unit. The masquerading option is provided with port forwarding to limit gateway forwarding only to the destination port. (Required field).
Permitted Network: only forwards if the packet is originated from a host on this network.
Permitted MAC Address: only forwards if the packet is originated by this host.
Source Port Range: only forwards if the packet's source port is within the defined range.
Complete the Port Forward Entry form and click the Apply button for the desired port forwarding rules to take effect.
The firewall rules related to the port forwarding section are stored in the forward-kura-pf custom chain of the IPv4/IPv6 filter table and in the postrouting-kura-pf and prerouting-kura-pf chains of the IPv4/IPv6 nat table.
"},{"location":"gateway-configuration/firewall-configuration/#port-forwarding-example","title":"Port Forwarding example","text":"This section describes an example of port forwarding rules applied to the IPv4 case. The initial setup is described below.
A couple of RaspberryPi that shares the same LAN over Ethernet.
The first RaspberryPi running Kura is configured as follows:
The second RaspberryPi running Kura is configured as follows:
A laptop is connected to the same network of the wlan0 of the second RaspberryPi and can ping its wlan0 interface.
The purpose of the second RaspberryPi configuration is to enable access to the Administration Console running on the first one (port 80) by connecting to the second RaspberryPi's port 8080 over the wlan. This scenario assumes that IP addresses are assigned as follows:
Second RaspberryPi wlan0 - 10.200.12.6
Laptop wlan0 - 10.200.12.10
The following port forwarding entries are added to the second RaspberryPi configuration as described above using the Port Forward Entry form:
Input Interface - wlan0
Output Interface - eth0
LAN Address - 172.16.0.5
Protocol - tcp
External Port - 8080
Internal Port - 80
Masquerade - yes
The Permitted Network, Permitted MAC Address, and Source Port Range fields are left blank.
The following iptables rules are applied and added to the /etc/sysconfig/iptables file:
iptables -t nat -A prerouting-kura-pf -i wlan0 -p tcp -s 0.0.0.0/0 --dport 8080 -j DNAT --to 172.16.0.5:80\niptables -t nat -A postrouting-kura-pf -o eth0 -p tcp -d 172.16.0.5 -j MASQUERADE\niptables -A forward-kura-pf -i wlan0 -o eth0 -p tcp -s 0.0.0.0/0 --dport 80 -d 172.16.0.5 -j ACCEPT\niptables -A forward-kura-pf -i eth0 -o wlan0 -p tcp -s 172.16.0.5 -m state --state RELATED,ESTABLISHED -j ACCEPT\n
The following iptables commands may be used to verify that the new rules have been applied:
sudo iptables -v -n -L\nsudo iptables -v -n -L -t nat\n
At this point, it is possible to try to connect to http://10.200.12.6 and to http://10.200.12.6:8080 from the laptop. Note that when a connection is made to the device on port 80, it is to the Kura configuration page on the device itself (the second RaspberryPi). When the gateway is connected on port 8080, you are forwarded to the Kura Gateway Administration Console on the first RaspberryPi. The destination host can only be reached by connecting to the gateway on port 8080.
Another way to connect to the Kura Gateway Administration Console on the first RaspberryPi would be to add an IP Forwarding/Masquerading entry as described in the next section.
"},{"location":"gateway-configuration/firewall-configuration/#ip-forwardingmasquerading","title":"IP Forwarding/Masquerading","text":"The advantage of the Automatic NAT method is its simplicity. However, this approach does not handle reverse NATing, and it cannot be used for interfaces that are not listed in the Gateway Administration Console (such as VPN tun0 interface). To set up generic (one-to-many) NATing, select the IP Forwarding/Masquerading IPv4 or IP Forwarding/Masquerading IPv6 tab on the Firewall display. Press the New button and the IP Forwarding/Masquerading form appears.
The IP Forwarding/Masquerading form contains the following configuration parameters:
Input Interface: specifies the interface through which a packet is going to be received. (Required field).
Output Interface: specifies the interface through which a packet is going to be forwarded to its destination. (Required field).
Protocol: defines the protocol of the rule to check (all, tcp, or udp). (Required field).
Source Network/Host: identifies the source network or host name (CIDR notation). Set to IPv4 0.0.0.0/0 or IPv6 ::/0 if empty.
Destination Network/Host: identifies the destination network or host name (CIDR notation). Set to IPv4 0.0.0.0/0 or IPv6 ::/0 if empty.
Enable Masquerading: defines whether masquerading is used (yes or no). If set to 'yes', masquerading is enabled. If set to 'no', only FORWARDING rules are be added. (Required field).
The rules will be added to the forward-kura-ipf chain in the IPv4/IPv6 filter table and in the postrouting-kura-ipf one in the IPv4/IPv6 nat table.
As a use-case scenario, consider the same setup as in port forwarding, but with cellular interface disabled and eth1 interface configured as WAN/DHCP client. In this case, the interfaces of the gateway are configured as follows:
eth0
: LAN/Static/No NAT 172.16.0.1/24
eth1
: WAN/DHCP 10.11.5.4/24
To reach the gateway sitting on the 172.16.0.5/24 from a specific host on the 10.11.0.0/16 network, set up the following Reverse NAT entry:
Input Interface: eth1 (WAN interface)
Output Interface: eth0 (LAN interface)
Protocol: all
Source Network/Host: 10.11.5.21/32
Destination Network/Host: 172.16.0.5/32
Enable Masquerading: yes
This case applies the following iptables rules:
iptables -t nat -A postrouting-kura-ipf -p tcp -s 10.11.5.21/32 -d 172.16.0.5/32 -o eth0 -j MASQUERADE\niptables -A forward-kura-ipf -p tcp -s 172.16.0.5/32 -i eth0 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT\niptables -A forward-kura-ipf -p tcp -s 10.11.5.21/32 -d 172.16.0.5/32 -i eth1 -o eth0 -m tcp -j ACCEPT\n
Additionally, a route to the 172.16.0.0/24 network needs to be configured on a connecting laptop as shown below:
sudo route add -net 172.16.0.0 netmask 255.255.255.0 gw 10.11.5.4\n
Since masquerading is enabled, there is no need to specify the back route on the destination host. Note that with this setup, the gateway only forwards packets originating on the 10.11.5.21 laptop to the 172.16.0.5 destination.
If the Source Network/Host and Destination Network/Host fields are empty, iptables rules appear as follows:
iptables -t nat -A postrouting-kura-ipf -p tcp -s 0.0.0.0/0 -d 0.0.0.0/0 -o eth0 -j MASQUERADE\niptables -A forward-kura-ipf -p tcp -s 0.0.0.0/0 -i eth0 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT\niptables -A forward-kura-ipf -p tcp -s 0.0.0.0/0 -d 0.0.0.0/0 -i eth1 -o eth0 -j ACCEPT\n
The gateway forwards packets from any external host (connected to eth1) to any destination on the local network (eth0 interface).
"},{"location":"gateway-configuration/gateway-administration-console-authentication/","title":"Gateway Administration Console Authentication","text":"The Gateway Administration Console supports multiple login identities with associated permissions and HTTPS client side authentication with certificates.
The identity and permission configuration and credentials is stored externally the UserAdmin service (see Authentication and Authorization for more details).
"},{"location":"gateway-configuration/gateway-administration-console-authentication/#permissions","title":"Permissions","text":"The Gateway Administration Console defines the following permissions, that allow to restrict the operations that an identity is allowed to perform:
Kura provides the following identities by default:
Name Password Permissions admin admin kura.admin appadmin appadmin kura.cloud.connection.admin, kura.packages.admin, kura.wires.admin netadmin netadmin kura.cloud.connection.admin, kura.device, kura.network.adminIt is possible to modify/remove the default identity configuration.
"},{"location":"gateway-configuration/gateway-administration-console-authentication/#login","title":"Login","text":"The login screen can be accessed by entering the https://${device.ip}
URL in a browser window, where ${device.ip}
is the IP address. Replace https
with http
if HTTPS support has been disabled on the gateway.
In order to login with identity name and password, select Password as authentication method and enter the credentials.
Note
Password authentication method might not be available if it has been disabled by the administrator using the Security -> Web Console section.
"},{"location":"gateway-configuration/gateway-administration-console-authentication/#forced-password-change-on-login","title":"Forced password change on login","text":"Kura supports forcing an identity to change the password at login, before accessing the Administration Console. This functionality is enabled by default after a fresh installation. At login the following prompt will appear forcing the user to define a new password.
This functionality can be configured by an admin identity using the Identities section of the Administration Console.
The forced password change can also be disabled by editing the snapshot_0.xml
file removing the kura.need.password.change
property for the desired identity in the org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl
configuration before Kura first boot. If this functionality is enabled, REST API username and password authentication is will be disabled for the specific identity until the password is updated, REST API certificate authentication will still work.
In order to perform HTTPS certificate authentication, select the Certificate authentication method and click Login, the browser may prompt to select the certificate to use.
Note
Certificate authentication method might not be available if no HTTPS with client authentication ports have been configured or if it has been explicitly disabled by the administrator using the Security -> Web Console section.
"},{"location":"gateway-configuration/gateway-administration-console-authentication/#identity-and-permission-management","title":"Identity and Permission management","text":"The Gateway Administration Console allows the management of identity and permission configuration in a dedicated view, accessible by navigating to the Identities section:
The section above allows to:
"},{"location":"gateway-configuration/gateway-administration-console-authentication/#create-new-identities","title":"Create new identities","text":"New identities can be created by clicking the New Identity button.
"},{"location":"gateway-configuration/gateway-administration-console-authentication/#remove-existing-identities","title":"Remove existing identities","text":"Existing identities can be removed by selecting the corresponding entry in the list and pressing the Delete Identity button.
"},{"location":"gateway-configuration/gateway-administration-console-authentication/#manage-password-authentication","title":"Manage password authentication","text":"Password authentication can be enabled or disabled by changing the Password authentication enabled parameter. Changing this parameter will not modify the existing stored password. Enabling password authentication for a new identity requires to define a new password. The password can be set/modified by clicking the Change password button.
"},{"location":"gateway-configuration/gateway-administration-console-authentication/#assign-or-remove-permissions","title":"Assign or remove permissions","text":"Permissions can be assigned or removed by ticking the corresponding entries in the Permissions table. No changes will be applied to the gateway until the Apply button is pressed.
"},{"location":"gateway-configuration/gateway-administration-console-authentication/#certificate-based-authentication","title":"Certificate based authentication","text":"The Gateway Administration Console supports HTTPS certificate based client side authentication. The authentication process works as follows:
One or more Https client certificate must be added to keystore, this can be done using the Certificate Management section.
The user must provide a certificate or certificate chain signed by one of the CAs added as Https client certificate.
The common name field of the leaf certificate provided by the user must be the name of the identity that should be used for the session.
HTTPS with certificate based authentication must be enabled in the HTTP/HTTPS Configuration section.
Log in with certificate can be performed by selecting the Certificate authentication method in Gateway Administration Console login screen or by connecting directly to the HTTPS port with client side authentication specified in gateway configuration.
"},{"location":"gateway-configuration/gateway-administration-console/","title":"Gateway Administration Console","text":""},{"location":"gateway-configuration/gateway-administration-console/#accessing-the-kura-gateway-administration-console","title":"Accessing the Kura Gateway Administration Console","text":"Kura provides a web-based, user interface for the administration and management of your IoT gateway. The Kura Gateway Administration Console enables you to monitor the gateway status, manage the network configuration, and manage the installed application and services. Access to the Kura Gateway Administration Console requires that a unit running Eclipse Kura is reachable via its Ethernet primary interface.
Connections on HTTP port 443 for these interfaces are allowed by default through the built-in firewall. The Kura Gateway Administration Console can be accessed by typing the IP address of the gateway into the browser's URL bar. Once the URL is submitted, the user is required to log in and is then redirected to the Administration Console (e.g., https://192.168.2.8/admin/console
) shown in the screen capture below. The default login name and password is admin/admin
.
Warning
It is recommended to change the default password after initial setup and before deployment, as well as limiting access to the Administration Console to a trusted local network interface using appropriate firewall rules.
"},{"location":"gateway-configuration/gateway-administration-console/#password-change","title":"Password change","text":"Once logged in, the user can modify its password (recommended after the first login). To access the option, click on the button near the username in the header section. A dropdown menu appears with the logout and the password modification options. When clicking on \"Change password\", the following dialog will appear:
After confirming the changes, the user will be logged out.
"},{"location":"gateway-configuration/gateway-administration-console/#accessing-the-kura-gateway-administration-console-over-a-cellular-link","title":"Accessing the Kura Gateway Administration Console over a Cellular Link","text":"In order to connect to the Gateway Administration Console via a cellular interface, the following requirements must be met:
If some of the used ports are blocked by the service provider, there is an option to reconfigure the gateway to use another port (i.e., 8080). In order to do so, the following requirements must be met:
Most browsers will probably warn the user that the connection is not secure when Gateway Administration Console is accessed using HTTPS.
In order to remove the warning, the browser must be able to verify the identity of the gateway as an HTTPS server. The verification process will fail with default server certificate provided by Kura because it is self-signed and it is not suitable for hostname verification.
Fixing this might require to configure the browser to trust the certificate provided by the gateway and/or using a server certificate signed by a CA trusted by the browser and assigning a DNS name to the gateway in order to pass hostname verification.
"},{"location":"gateway-configuration/gateway-administration-console/#system-use-notification-banner","title":"System Use Notification Banner","text":"For security reasons, it may be needed to display to the user a banner that describes the intended system use before authenticating. The system use notification message is customisable by authorised personnel in the Security section of the Kura Web UI, in the Web Console tab.
"},{"location":"gateway-configuration/gateway-status/","title":"Gateway Status","text":"The status of the gateway may be viewed from the Status window, which is accessed by selecting the Status option located in the System area. The Status window provides a summary of the key information regarding the status of the gateway including its IoT Cloud connection and network configuration.
The values reported in the page can be reloaded using the Refresh button. This will read the current values from the system and update the page. Since the update procedure can take time, the update can be performed at most every 30 seconds.
"},{"location":"gateway-configuration/gateway-status/#cloud-services","title":"Cloud Services","text":"This section provides a summary of the IoT Cloud connection status including the following details:
This section provides information about the currently configured network interfaces.
"},{"location":"gateway-configuration/gateway-status/#position-status","title":"Position Status","text":"This section provides the GPS status and latest known position (if applicable) including the following details:
Warning
The status reported in the page may not be synchronized with the real state of the system. In this case, use the Refresh button to updated the values in the page.
"},{"location":"gateway-configuration/keys-and-certificates/","title":"Keys and Certificates","text":"The framework manages directly different key pairs and trusted certificates from different keystores. To simplify the management of such complex objects, the framework provides a dedicated section of its Administrative Web UI, a set of REST APIs for local management and a request handler (KEYS-V1 and KEYS-V2) for cloud remote interaction.
"},{"location":"gateway-configuration/keys-and-certificates/#web-ui","title":"Web UI","text":"The Certificates List tab in the Security section of the Kura Web UI provides a simple way for the user to get the list of all the managed keys and certificates of the framework:
The page allows the user to add a new Keypair or trusted certificate or to delete an existing element.
Every key pair or trusted certificate is listed by its alias, identified by the corresponding type and further identified by the keystore that is managing that element.
If the user needs to add a new entry to one of the managed KeystoreService instances, can click on the Add button on the top left part of the page. The user will be guided through a process that will allow to identify the type of entry to add:
It can be either a:
If the user decides to add a key pair, then the wizard will provide a page like the following:
Here the user can specify: - Key Store: the KeystoreService instance that will store and maintain the key pair - Storage Alias: the alias that will be used to identify the key pair - Private Key: the private key part of the key pair - Certificate: the public key part of the key pair
After clicking on the Apply button, the new entry will be stored in the selected Keystore and listed along the other entries managed by the framework.
The following cryptographic algorithms are supported for Key Pairs: - RSA - DSA
Instead, if the user wants to load a Trusted Certificate, the Ui will change as follows:
Here the user can specify: - Key Store: the KeystoreService instance that will store and maintain the trusted certificate - Storage Alias: the alias that will be used to identify the trusted certificate - Certificate: the trusted certificate
The following cryptographic algorithms are supported for Trusted Certificates: - RSA - DSA - EC
"},{"location":"gateway-configuration/keys-and-certificates/#rest-apis","title":"REST APIs","text":""},{"location":"gateway-configuration/keys-and-certificates/#keystoresv1","title":"keystores/v1","text":"The org.eclipse.kura.core.keystore
bundle exposes a REST endpoint under the /services/keystores/v1
path. The Kura REST APIs for Keys and Certificates support the following calls and are allowed to any user with rest.keystores
permission.
/
keystores JSON None Returns the list of all the KeystoreService instances. GET /entries
keystores JSON None Returns the list of all the entries managed by the KeystoreService instances. GET /entries?keystoreServicePid={keystoreServicePid}
keystores JSON keystoreServicePid Returns the list of all the entries managed by the specified KeystoreService instance. GET /entries?alias={alias}
keystores JSON alias Returns the list of all the entries specified by the defined alias and managed in all the available KeystoreService instances in the framework. GET /entries/entry?keystoreServicePid={keystoreServicePid}&alias={alias}
keystores JSON keystoreServicePid and alias Returns the entry identified by the specified keystoreServicePid and alias. POST /entries/csr
keystores JSON The reference to the key pair in a specified KeystoreService instance that will be used to generate the CSR. The request has to be associated with additional parameters that identify the algorithm used to compute and sign the CSR and the DN or the corresponding public key that needs to be countersigned. Generates a CSR for the specified key pair in the specified KeystoreService instance, based on the parameters provided in the request. POST /entries/certificate
keystores JSON The reference to the KeystoreService instance and the alias that will be used for storage. A type filed identifies the type of key that needs to be managed. This request allows the user to upload a TrustedCertificate. POST /entries/keypair
keystores JSON To generate a new KeyPair directly in the device, the request format need to follow the references in the following paragraphs. This request allows the user to generate a new KeyPair into the device. DELETE /entries
keystores JSON A JSON identifying the resource to delete. The format of the request is described in in one of the following sections. Deletes the entry in the specified KeystoreService instance."},{"location":"gateway-configuration/keys-and-certificates/#list-all-the-keystoreservices","title":"List All the KeystoreServices","text":"Request: URL - https://<gateway-ip>/services/keystores/v1
Response:
[\n {\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.SSLKeystore\",\n \"type\": \"jks\",\n \"size\": 4\n },\n {\n \"keystoreServicePid\": \"org.eclipse.kura.crypto.CryptoService\",\n \"type\": \"jks\",\n \"size\": 3\n },\n {\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.HttpsKeystore\",\n \"type\": \"jks\",\n \"size\": 1\n },\n {\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.DMKeystore\",\n \"type\": \"jks\",\n \"size\": 1\n }\n]\n
"},{"location":"gateway-configuration/keys-and-certificates/#get-all-the-managed-entries","title":"Get all the Managed Entries","text":"Request: URL - https://<gateway-ip>/services/keystores/v1/entries
Response:
[\n {\n \"subjectDN\": \"OU=Go Daddy Class 2 Certification Authority, O=\\\"The Go Daddy Group, Inc.\\\", C=US\",\n \"issuer\": \"OU=Go Daddy Class 2 Certification Authority,O=The Go Daddy Group\\\\, Inc.,C=US\",\n \"startDate\": \"Tue, 29 Jun 2004 17:06:20 GMT\",\n \"expirationDate\": \"Thu, 29 Jun 2034 17:06:20 GMT\",\n \"algorithm\": \"SHA1withRSA\",\n \"size\": 2048,\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.SSLKeystore\",\n \"alias\": \"ca-godaddyclass2ca\",\n \"type\": \"TRUSTED_CERTIFICATE\"\n },\n {\n \"algorithm\": \"RSA\",\n \"size\": 4096,\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.HttpsKeystore\",\n \"alias\": \"localhost\",\n \"type\": \"PRIVATE_KEY\"\n }\n]\n
"},{"location":"gateway-configuration/keys-and-certificates/#get-all-the-entries-by-keystoreservice","title":"Get All the Entries by KeystoreService","text":"Request: URL - https://<gateway-ip>/services/keystores/v1/entries?keystoreServicePid=org.eclipse.kura.core.keystore.HttpsKeystore
Response:
[\n {\n \"algorithm\": \"RSA\",\n \"size\": 4096,\n \"certificateChain\": [\n \"-----BEGIN CERTIFICATE-----\\n<CERTIFICATE>\\n-----END CERTIFICATE-----\"\n ],\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.HttpsKeystore\",\n \"alias\": \"localhost\",\n \"type\": \"PRIVATE_KEY\"\n }\n]\n
"},{"location":"gateway-configuration/keys-and-certificates/#get-all-the-entries-by-alias","title":"Get All the Entries by Alias","text":"Request: URL - https://<gateway-ip>/services/keystores/v1/entries?alias=localhost
Response:
[\n {\n \"algorithm\": \"RSA\",\n \"size\": 4096,\n \"certificateChain\": [\n \"-----BEGIN CERTIFICATE-----\\n<CERTIFICATE>\\n-----END CERTIFICATE-----\"\n ],\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.HttpsKeystore\",\n \"alias\": \"localhost\",\n \"type\": \"PRIVATE_KEY\"\n }\n]\n
"},{"location":"gateway-configuration/keys-and-certificates/#get-specific-entry","title":"Get Specific Entry","text":"Request: URL - https://<gateway-ip>/services/keystores/v1/entries/entry?keystoreServicePid=org.eclipse.kura.core.keystore.HttpsKeystore&alias=localhost
Response:
{\n \"algorithm\": \"RSA\",\n \"size\": 4096,\n \"certificateChain\": [\n \"-----BEGIN CERTIFICATE-----\\n<CERTIFICATE>-----END CERTIFICATE-----\"\n ],\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.HttpsKeystore\",\n \"alias\": \"localhost\",\n \"type\": \"PRIVATE_KEY\"\n}\n
"},{"location":"gateway-configuration/keys-and-certificates/#get-the-csr-for-a-keypair","title":"Get the CSR for a KeyPair","text":"Request: URL - https://<gateway-ip>/services/keystores/v1/entries/csr
keystoreServicePid=org.eclipse.kura.core.keystore.HttpsKeystore&alias=localhost`
Request body:
{ \n \"keystoreServicePid\":\"org.eclipse.kura.core.keystore.HttpsKeystore\",\n \"alias\":\"localhost\",\n \"signatureAlgorithm\" : \"SHA256withRSA\",\n \"attributes\" : \"CN=Kura, OU=IoT, O=Eclipse, C=US\"\n}\n
"},{"location":"gateway-configuration/keys-and-certificates/#store-trusted-certificate","title":"Store Trusted Certificate","text":"Request: URL - https://<gateway-ip>/services/keystores/v1/entries/certificate
Request body:
{\n \"keystoreServicePid\":\"MyKeystore\",\n \"alias\":\"myCertTest99\",\n \"certificate\":\"-----BEGIN CERTIFICATE-----\n <CERTIFICATE>\n -----END CERTIFICATE-----\"\n}\n
"},{"location":"gateway-configuration/keys-and-certificates/#generate-keypair","title":"Generate KeyPair","text":"Request: URL - https://<gateway-ip>/services/keystores/v1/entries/keypair
Request body:
{\n \"keystoreServicePid\":\"MyKeystore\",\n \"alias\":\"keypair1\",\n \"algorithm\" : \"RSA\",\n \"size\": 1024,\n \"signatureAlgorithm\" : \"SHA256WithRSA\",\n \"attributes\" : \"CN=Kura, OU=IoT, O=Eclipse, C=US\"\n}\n
"},{"location":"gateway-configuration/keys-and-certificates/#delete-entry","title":"Delete Entry","text":"Request: URL - https://<gateway-ip>/services/keystores/v1/entries
Request body:
{\n \"keystoreServicePid\" : \"MyKeystore\",\n \"alias\" : \"mycerttestec\"\n}\n
"},{"location":"gateway-configuration/keys-and-certificates/#keys-v1-request-handler","title":"KEYS-V1 Request Handler","text":"Mapping the previously defined REST APIs, the framework exposed to the remote cloud platforms a request handler named KEYS-V1 that allows the remote user to list and manage the keystores, the keys and the certificates in the framework.
The request handler exposes also the capability to generate on the edge a CSR that can be countersigned remotely by a trusted CA.
"},{"location":"gateway-configuration/keys-and-certificates/#keystoresv2","title":"keystores/v2","text":"Starting from Kura 5.4.0, the keystores/v2
REST API is also available, it supports all of the request endpoints of keystores/v1
plus an additional endpoint that allows to upload and modify private key entries:
/entries/privatekey
keystores JSON To upload a new private key entry directly in the device, the request format need to follow the references in the following paragraphs. This request allows the user to upload a new private key entry into the device or to modify the certificate chain of an existing one."},{"location":"gateway-configuration/keys-and-certificates/#uploading-a-private-key-entry","title":"Uploading a Private Key Entry","text":"Request: URL - https://<gateway-ip>/services/keystores/v2/entries/privatekey
Request body:
The request should include the private key in unencrypted PEM format and the certificate chain in PEM format, the first certificate in the certificateChain
list must use the public key associated with the private key supplied as the privateKey
parameter.
The device will overwrite the entry with the provided alias if it already exists.
WARINING: Please use this endpoint through a secure connection.
{\n \"keystoreServicePid\":\"MyKeystore\",\n \"alias\":\"keypair1\",\n \"privateKey\":\"-----BEGIN RSA PRIVATE KEY-----\\n...\\n-----END RSA PRIVATE KEY-----\",\n \"certificateChain\":[\n \"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\",\n \"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\",\n ]\n}\n
"},{"location":"gateway-configuration/keys-and-certificates/#updating-a-private-key-entry","title":"Updating a Private Key Entry","text":"Request: URL - https://<gateway-ip>/services/keystores/v2/entries/privatekey
Request body:
In order to update the certificate chain associated to a specific private key entry it is possible to use the same format as previous request and omit the privateKey
parameter.
In this case the certificate chain of the existing entry will be replaced with the one specified in the request and the existing private key will be retained.
This request can be useful for example to create a CSR on the device, sign it externally and then updating the corresponding entry with the resulting certificate.
{\n \"keystoreServicePid\":\"MyKeystore\",\n \"alias\":\"keypair1\",\n \"certificateChain\":[\n \"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\",\n \"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\",\n ]\n}\n
"},{"location":"gateway-configuration/keystores-management/","title":"Keystores Management","text":"The framework manages different types of cryptographic keys and certificates. In order to simplify the interaction with those objects, Kura provides a KeystoreService API and a specific section in the Kura Web UI that lists all the available KeystoreService instances.
From the Security section, a user with Security permissions can access the Keystore Configuration section. A list of all the framework managed keystores will be available to the user with the Service PID that will be used by other components to reference the selected keystore. Associated to the Service PID, the UI shows the Factory PID that identifies the specific KeystoreService API implementation that is providing the service to the framework.
In order to modify the configuration of a specific keystore service instance, the user can select one of the available rows, obtaining the corresponding keystore service configuration.
The following KeystoreService factories are available:
"},{"location":"gateway-configuration/keystores-management/#filesystemkeystoreserviceimpl","title":"FilesystemKeystoreServiceImpl","text":"The org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl
factory provides a KeystoreService implementation that stores the private keys and certificates as a file. The user can customise the following options:
The org.eclipse.kura.core.keystore.PKCS11KeystoreServiceImpl
factory provides a KeystoreService implementation that allows to access a PKCS11 token through the SunPKCS11 implementation.
At the moment this type of KeystoreService provides read only access to the underlying token, operations such as adding or removing entries will fail.
It is possible to use the entries provided by a PKCS11KeystoreServiceImpl
for SSL authentication.
The available configuration options closely match the parameters provided by the SunPKCS11 implementation, see the official documentation for more details.
In particular, the official documentation contains a section that explains how the PKCS11 objects are mapped to Java KeyStore entries.
The only required parameter is the PKCS11 Implementation Library Path parameter. It is usually also necessary to specify the token user pin as the Pin parameter.
The configuration parameters are mapped to the SunPKCS11 provider parameters in the following way:
Kura Parameter SunPKCS11 Parameter Notes Slot slot Slot List Index slotListIndex Enabled Mechanisms enabledMechanisms The curly braces must be omitted Disabled Mechanisms disabledMechanisms The curly braces must be omitted. Attributes attributes The value of this field will be appended to the provider configuration."},{"location":"gateway-configuration/network-advanced/","title":"Advanced Network Settings","text":"For devices running Kura installed using a Generic Profile, it is possible to to fine tune network traffic settings. Take a look at our installer profiles to know which are supported.
The Advanced configuration tab is designed for users who seek a higher level of control and customization over their network experience. Whether you are an IT professional, network administrator, or enthusiast looking to fine-tune specific aspects of your network, this tab provides access to advanced parameters like Maximum Transmission Unit (MTU) and Promiscuous Mode. Adjusting these settings allows for optimized performance in unique network environments, troubleshooting capabilities, and enhanced security monitoring. Please exercise caution when modifying these settings, ensuring that you have a clear understanding of their implications on your network's behavior.
Tip
Some parameters requires a minimum version of NetworkManager, as described below and in Kura UI. The System Component Inventory can be used to check what version is available on your device.
The Advanced tab allow configuration of:
The Advanced tab contains the following configuration parameters:
Warning
The MTU value for a VLAN is limited by the configured MTU of its parent interface as an upper bound.
To configure the gateway network interfaces using the Gateway Administration Console, select the Network option located in the System area. With this option selected, the Network display appears with a list of available interfaces. Configuration tabs for the selected interface appear on the right side of the screen. By default, the loopback (lo) interface is selected when the network interfaces are displayed. Choose the desired network interface (e.g., eth0, eth1, wlan0, ppp0) and apply the necessary configuration changes using the tabs on the right. Submit the modified configuration by clicking the Apply button.
In case of typing errors, the Reset button can be used to reload the prior configuration on the screen. Since the network configuration shown on the screen may not be synchronized with the current state of the system, it can be updated pressing the Refresh button. This can be used also to force the reload of specific parameters like the RSSI or dynamic IP addresses. The refresh procedure reads all the needed parameters from the system and can take several seconds before updating.
Tip
It is recommended that the TCP/IP tab is configured first since it defines how the interface is going to be used.
"},{"location":"gateway-configuration/network-configuration/#tcpip-configuration","title":"TCP/IP Configuration","text":"The TCP/IP tab contains the following configuration parameters:
If the network interface is Enabled for LAN and manually configured (i.e., not a DHCP client), the DHCP & NAT tab allows the DHCP server to be configured and/or NAT (IP forwarding with masquerading) to be enabled.
"},{"location":"gateway-configuration/network-configuration/#more-details-about-the-not-managed-interface-status","title":"More details about the Not Managed interface Status","text":"When a network interface is configured as Not Managed, Kura will ignore it and the configuration will not be touched. The user can configure the interface with the network tools provided by the OS, allowing unusual network setups.
Regarding DNS, both Kura and the external tools store the DNS addresses in the /etc/resolv.conf
file. So, if multiple interfaces are configured to get the DNS information and store it in the same file, the device can be misconfigured. To avoid that, the following table presents who is responsible to update the DNS file depending on the network interfaces configurations.
WAN
? Is there at least one interface set as Not Managed
? Does Kura manage resolv.conf? NO NO YES NO YES NO YES NO YES YES YES YES So, the only way to configure the DNS addresses with external tools, is to configure at least one interface as Not Managed and not to set any interface as Enabled For Wan using Kura. If at least one WAN interface is configured by Kura, it will take the control of the /etc/resolv.conf/
file. Finally, if any interface is configured in Enabled For Wan or Not Managed mode, Kura will empty the file.
To avoid device misconfigurations when Not Managed interfaces are used, don't use the dns-nameservers directive in the /etc/network/interfaces
file. Please add the DNS addresses directly to the /etc/resolv.conf
file.
The DHCP & NAT tab contains the following configuration parameters:
If NAT is enabled and there is another interface designated as WAN (e.g., ppp0), the following iptables rules are added to the custom automatic NAT service rules_* section of the /etc/init.d/firewall
script:
# custom automatic NAT service rules (if NAT option is enabled for LAN interface)\niptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE\niptables -A FORWARD -i ppp0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT\niptables -A FORWARD -i eth0 -o ppp0 -j ACCEPT\n
Also, IP forwarding is enabled in the kernel as follows:
# allow fowarding if any masquerade is defined\necho 1 > /proc/sys/net/ipv4/ip_forward\n
The rules shown above create an Overloaded_ (i.e., many-to-one) NAT. This type of network address translation maps multiple IP addresses on the LAN side to a single IP address on the WAN side, allowing internet access from hosts on a local network via a gateway (WAN) interface. Note that for NAT rules to be added, it is insufficient to enable NATing through the DHCP & NAT* tab of the LAN interface; there must also be another interface designated as WAN.
"},{"location":"gateway-configuration/network-configuration/#network-linux-configuration","title":"Network Linux Configuration","text":"When applying a new network configuration, Kura changes the configuration files of the Linux networking subsystem. Please read the following note before proceeding with manual changes of the Linux networking configuration.
Warning
It is NOT recommended performing manual editing of the Linux networking configuration files when the gateway configuration is being managed through Kura. While Linux may correctly accept manual changes, Kura may not be able to interpret the new configuration resulting in an inconsistent state.
"},{"location":"gateway-configuration/network-configuration/#network-configuration-properties","title":"Network Configuration properties","text":"The Network configuration can be modified using the Kura Gateway Administration Console, as described above, the Configuration Service or appling a proper snapshot.
The following table describes all the properties related to the Network Configuration. It includes the name of the property, the type, a description and the default value (if applicable). The network configuration pid is org.eclipse.kura.net.admin.NetworkConfigurationService
.
net.interfaces
String Comma-separated list of the interface names in the device net.interface.<interface>.type
String The type of the network interface; possible values are: ETHERNET
, WIFI
, MODEM
, VLAN
, LOOPBACK
and UNKNOWN
UNKNOWN
net.interface.<interface>.config.wifi.mode
String For wifi interfaces, specify the modality; possible values are INFRA
, MASTER
and UNKNOWN
UNKNOWN
net.interface.<interface>.config.nat.enabled
Boolean Enable the NAT feature false net.interface.<interface>.config.promisc
Integer Enable the Promiscuous Mode; possible values are: -1 (System default), 0 (Disabled), 1 (Enabled) -1"},{"location":"gateway-configuration/network-configuration/#ipv4-properties","title":"IPv4 properties","text":"Name Type Description Default value net.interface.<interface>.config.ip4.status
String The status of the interface for the IPv4 configuration; possibile values are: netIPv4StatusDisabled
, netIPv4StatusUnmanaged
, netIPv4StatusL2Only
, netIPv4StatusEnabledLAN
, netIPv4StatusEnabledWAN
, netIPv4StatusUnknown
netIPv4StatusDisabled
(see note below) net.interface.<interface>.config.ip4.wan.priority
Integer (NetworkManager only) Priority used to determine which interface select as primary WAN. Allowed values range from -1 to 2147483647, inclusive. See Network Failover for further details -1 net.interface.<interface>.config.ip4.address
String The IPv4 address assigned to the network interface net.interface.<interface>.config.ip4.prefix
Short The IPv4 netmask assigned to the network interface -1 net.interface.<interface>.config.ip4.gateway
String The IPv4 address of the default gateway net.interface.<interface>.config.ip4.dnsServers
String Comma-separated list of dns servers net.interface.<interface>.config.ip4.mtu
Integer The Maximum Transition Unit (MTU) for this interface Note
For physical interfaces the default status is netIPv4StatusDisabled
. For virtual ones, instead, the default status is defined by the kura.net.virtual.devices.config
property in the kura.properties
file.
net.interface.<interface>.config.dhcpServer4.enabled
Boolean Specify if the DHCP server is enabled false net.interface.<interface>.config.dhcpServer4.rangeStart
String First IP address available for clients net.interface.<interface>.config.dhcpServer4.rangeEnd
String Last IP address available for clients net.interface.<interface>.config.dhcpServer4.defaultLeaseTime
Integer The default lease time -1 net.interface.<interface>.config.dhcpServer4.maxLeaseTime
Integer The maximum lease time -1 net.interface.<interface>.config.dhcpServer4.prefix
Short The netmask for the available IP addresses -1 net.interface.<interface>.config.dhcpServer4.passDns
Boolean Specify if the DNS server addresses has to be passed through DHCP false"},{"location":"gateway-configuration/network-configuration/#ipv4-dhcp-client-properties","title":"IPv4 DHCP Client properties","text":"Name Type Description Default value net.interface.<interface>.config.dhcpClient4.enabled
Boolean Specify if the DHCP client is enabled false"},{"location":"gateway-configuration/network-configuration/#ipv6-properties","title":"IPv6 properties","text":"Name Type Description Default value net.interface.<interface>.config.ip6.status
String The status of the interface for the IPv6 configuration; possibile values are: netIPv6StatusDisabled
, netIPv6StatusUnmanaged
, netIPv6StatusL2Only
, netIPv6StatusEnabledLAN
, netIPv6StatusEnabledWAN
, netIPv6StatusUnknown
netIPv6StatusDisabled
(see note below) net.interface.<interface>.config.ip6.wan.priority
Integer (NetworkManager only) Priority used to determine which interface select as primary WAN. Allowed values range from -1 to 2147483647, inclusive. See Network Failover for further details -1 net.interface.<interface>.config.ip6.address.method
String The IPv6 configuration method; possible values are: AUTO
, DHCP
, MANUAL
. AUTO
net.interface.<interface>.config.ip6.address
String The IPv6 address assigned to the network interface net.interface.<interface>.config.ip6.prefix
Short The IPv6 netmask assigned to the network interface -1 net.interface.<interface>.config.ip6.gateway
String The IPv6 address of the default gateway net.interface.<interface>.config.ip6.dnsServers
String Comma-separated list of dns servers net.interface.<interface>.config.ip6.addr.gen.mode
String The IPv6 address generation mode; possible values are EUI64
, STABLE_PRIVACY
net.interface.<interface>.config.ip6.privacy
String The IPv6 Privacy Extensions for SLAAC; possible values are DISABLED
, ENABLED_PUBLIC_ADD
, ENABLED_TEMP_ADD
net.interface.<interface>.config.ip6.mtu
Integer The Maximum Transition Unit (MTU) for Ipv6 traffic on this interface. Requires NetworkManager 1.40 or newer Note
For physical interfaces the default status is netIPv6StatusDisabled
. For virtual ones, instead, the default status is defined by the kura.net.virtual.devices.config
property in the kura.properties
file.
net.interface.<interface>.config.wifi.master.driver
String The driver used for the connection net.interface.<interface>.config.wifi.master.passphrase
Password The password for the access point net.interface.<interface>.config.wifi.master.ssid
String The SSID of the access point net.interface.<interface>.config.wifi.master.securityType
String The security protocol for the wireless network; possible values are SECURITY_NONE
, SECURITY_WEP
, SECURITY_WPA
, SECURITY_WPA2
, SECURITY_WPA_WPA2
SECURITY_NONE
net.interface.<interface>.config.wifi.master.mode
String The mode of the wireless connection; for the access point mode set it to MASTER
MASTER
net.interface.<interface>.config.wifi.master.channel
String The channel to be used for the access point 1 net.interface.<interface>.config.wifi.master.radioMode
String Specify the 802.11 radio mode; possible values are RADIO_MODE_80211a
, RADIO_MODE_80211b
, RADIO_MODE_80211g
, RADIO_MODE_80211nHT20
, RADIO_MODE_80211_AC
RADIO_MODE_80211b
net.interface.<interface>.config.wifi.master.ignoreSSID
Boolean Specify if the SSID broadcast is ignored false net.interface.<interface>.config.wifi.master.groupCiphers
String Group ciphers i.e. group/broadcast encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms set, possible values are CCMP
, TKIP
, and CCMP_TKIP
CCMP_TKIP
net.interface.<interface>.config.wifi.master.pairwiseCiphers
String Pairwise ciphers i.e. pairwise encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms set, possible values are CCMP
, TKIP
, and CCMP_TKIP
CCMP_TKIP
"},{"location":"gateway-configuration/network-configuration/#wifi-infra-station-mode-properties","title":"WiFi Infra (Station Mode) properties","text":"Name Type Description Default value net.interface.<interface>.config.wifi.infra.ssid
String The SSID of the wireless network to connect to net.interface.<interface>.config.wifi.infra.channel
String The channel of the wireless network to connect to 1 net.interface.<interface>.config.wifi.infra.bgscan
String Set the background scans; possible values have the form <mode>:<shortInterval>:<rssiThreshold>:<longInterval>
where mode
(String) is one of NONE, SIMPLE, or LEARN, shortInterval
(Integer) sets the Bgscan short interval (secs), rssiThreshold
(Integer) sets the Bgscan Signal strength threshold (dBm), and longInterval
(Integer) sets the Bgscan long interval (secs) net.interface.<interface>.config.wifi.infra.passphrase
Password The password for the wireless network net.interface.<interface>.config.wifi.infra.ignoreSSID
Boolean Specify if a scan for SSID is required before attempting to associate false net.interface.<interface>.config.wifi.infra.mode
String The mode of the wireless connection; for station mode set to INFRA
INFRA
net.interface.<interface>.config.wifi.infra.pingAccessPoint
Boolean Enable pinging the access point after connection is established false net.interface.<interface>.config.wifi.infra.driver
String The driver used for the connection net.interface.<interface>.config.wifi.infra.securityType
String The security protocol for the wireless network; possible values are SECURITY_NONE
, SECURITY_WEP
, SECURITY_WPA
, SECURITY_WPA2
, SECURITY_WPA_WPA2
SECURITY_NONE
net.interface.<interface>.config.wifi.infra.groupCiphers
String Group ciphers i.e. group/broadcast encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms set, possible values are CCMP
, TKIP
, and CCMP_TKIP
CCMP_TKIP
net.interface.<interface>.config.wifi.infra.pairwiseCiphers
String Pairwise ciphers i.e. pairwise encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms set, possible values are CCMP
, TKIP
, and CCMP_TKIP
CCMP_TKIP
"},{"location":"gateway-configuration/network-configuration/#cellular-modem-properties","title":"Cellular Modem properties","text":"Name Type Description Default value net.interface.<interface>.config.enabled
Boolean Enable the interface false net.interface.<interface>.config.idle
Integer The idle option of the PPP daemon 95 net.interface.<interface>.config.username
String The username used for the connection net.interface.<interface>.config.password
Password The password used for the connection net.interface.<interface>.config.pdpType
String The PdP type; possible values are IP, PPP and IPv6 IP net.interface.<interface>.config.maxFail
Integer The maxfail option of the PPP daemon 5 net.interface.<interface>.config.authType
String The authentication type; possible values are NONE
, AUTO
, CHAP
and PAP
NONE
net.interface.<interface>.config.lpcEchoInterval
Integer The lcp-echo-interval option of the PPP daemon 0 net.interface.<interface>.config.activeFilter
String The active-filter option of the PPP daemon inbound net.interface.<interface>.config.lpcEchoFailure
Integer The lcp-echo-failure option of the PPP daemon 0 net.interface.<interface>.config.diversityEnabled
Boolean Enable the LTE diversity antenna false net.interface.<interface>.config.resetTimeout
Integer The modem reset timeout in minutes 5 net.interface.<interface>.config.gpsEnabled
Boolean Enable the GPS device in the modem if available false net.interface.<interface>.config.gpsMode
String Select the GPS mode to activate for the modem if available kuraModemGpsModeUnmanaged
net.interface.<interface>.config.persist
Boolean The persist option of the PPP daemon true net.interface.<interface>.config.apn
String The modem Access Point Name net.interface.<interface>.config.dialString
String The dial string used for connecting to the APN net.interface.<interface>.config.holdoff
Integer The holdoff option of the PPP daemon (in seconds) 1 net.interface.<interface>.config.pppNum
Integer Assigned ppp interface number 0"},{"location":"gateway-configuration/network-configuration/#gps-mode","title":"GPS Mode","text":"The GPS mode can be set to one of the following values:
kuraModemGpsModeUnmanaged
: the GPS device of the modem will be setup but not directly managed, therefore freeing the serial port for other services to use. This can be used in order to perform the setup of the GPS and then have another service (like gpsd
) parse the NMEA strings in order to extract the position informations. This is the default value.kuraModemGpsModeManagedGps
: the GPS device of the modem will be setup and directly managed (typically by ModemManager) therefore the serial port won't be available for other services to use.For older versions compatibility, if the net.interface.<interface>.config.gpsMode
property is not set, the GPS mode will be automatically set to the kuraModemGpsModeUnmanaged
equivalent.
net.interface.<interface>.config.vlan.parent
String Physical interface Vlan is bound to net.interface.<interface>.config.vlan.id
Integer Vlan tag identifier, between 0 and 4094 net.interface.<interface>.config.vlan.ingress
String Incoming traffic priorities in the format from:to, as comma separated pairs of unsigned integers (Optional) net.interface.<interface>.config.vlan.egress
String Outgoing traffic priorities in the format from:to, as comma separated pairs of unsigned integer (Optional) net.interface.<interface>.config.vlan.flags
String Configuration flags, between 0 and 15 (Optional) 1"},{"location":"gateway-configuration/network-configuration/#8021x-properties","title":"802.1x properties","text":"Name Type Description net.interface.<interface>.config.802-1x.eap
String The EAP method to be used when authenticating to the network with 802.1x. Supported methods: \"Kura8021xEapTls\", \"Kura8021xEapPeap\", \"Kura8021xEapTtls\". net.interface.<interface>.config.802-1x.innerAuth
String Specifies the \"phase 2\" inner authentication method when an EAP method that uses an inner TLS tunnel is specified in the \"eap\" property. Supported methods: \"Kura8021xInnerAuthNone\", \"Kura8021xInnerAuthMschapv2\". net.interface.<interface>.config.802-1x.identity
String Identity string for EAP authentication methods. Typically the user's user or login name. net.interface.<interface>.config.802-1x.password
String Password used for EAP authentication methods. net.interface.<interface>.config.802-1x.client-cert-name
String Name referring to the corresponding Kura keystore entry containing the client certificate if used by the EAP method specified in the \"eap\" property. Typically is set to the same name as the net.interface.<interface>.config.802-1x.private-key-name
when using EAP-TLS. net.interface.<interface>.config.802-1x.private-key-name
String Name referring to the corresponding Kura keystore entry containing the private key when the \"eap\" property is set to \"Kura8021xEapTls\". Typically is set to the same name as the net.interface.<interface>.config.802-1x.client-cert-name
. net.interface.<interface>.config.802-1x.ca-cert-name
String Name referring to the corresponding Kura keystore entry containing the CA certificate if used by the EAP method specified in the \"eap\" property. This parameter is optional but this allows man-in-the-middle attacks and is NOT recommended. net.interface.<interface>.config.802-1x.anonymous-identity
String Anonymous identity string for EAP authentication methods. Used as the unencrypted identity with EAP types that support different tunneled identity like EAP-TTLS (Optional)"},{"location":"gateway-configuration/network-configuration/#network-configuration-recipes","title":"Network Configuration recipes","text":"This section presents some snapshot examples to perform basic operations on networking. The snippets can be modified adapting them to the required configuration (i.e. changing the interface name in the property to be applied).
Warning
Be aware that an inconsitent or wrong configuration can compromise the network functionality of the gateway. Try the new configuration on a test device before appling it in a production environment!
Moreover, if a property is not present in the new snapshot, the old value is used for the configuration. So, the best practice is to set all the needed properties in the snapshot.
"},{"location":"gateway-configuration/network-configuration/#disable-a-network-interface","title":"Disable a network interface","text":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n <esf:configuration pid=\"org.eclipse.kura.net.admin.NetworkConfigurationService\">\n <esf:properties>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.type\" type=\"String\">\n <esf:value>ETHERNET</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.ip4.status\" type=\"String\">\n <esf:value>netIPv4StatusDisabled</esf:value>\n </esf:property>\n </esf:properties>\n </esf:configuration>\n</esf:configurations>\n
"},{"location":"gateway-configuration/network-configuration/#configure-an-ethernet-interface-for-wan-with-dhcp-client-enabled-and-custom-dns-server","title":"Configure an ethernet interface for WAN with DHCP client enabled and custom DNS server","text":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n <esf:configuration pid=\"org.eclipse.kura.net.admin.NetworkConfigurationService\">\n <esf:properties>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.type\" type=\"String\">\n <esf:value>ETHERNET</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.ip4.dnsServers\" type=\"String\">\n <esf:value>1.2.3.4</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.dhcpClient4.enabled\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.dhcpServer4.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.ip4.status\" type=\"String\">\n <esf:value>netIPv4StatusEnabledWAN</esf:value>\n </esf:property>\n </esf:properties>\n </esf:configuration>\n</esf:configurations>\n
"},{"location":"gateway-configuration/network-configuration/#configure-an-ethernet-interface-for-lan-with-dhcp-server-enabled-and-nat-disabled","title":"Configure an ethernet interface for LAN with DHCP server enabled and NAT disabled","text":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n <esf:configuration pid=\"org.eclipse.kura.net.admin.NetworkConfigurationService\">\n <esf:properties>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.type\" type=\"String\">\n <esf:value>ETHERNET</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.ip4.dnsServers\" type=\"String\">\n <esf:value/>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.dhcpClient4.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.ip4.status\" type=\"String\">\n <esf:value>netIPv4StatusEnabledLAN</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.dhcpServer4.rangeEnd\" type=\"String\">\n <esf:value>192.168.4.110</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.dhcpServer4.enabled\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.dhcpServer4.defaultLeaseTime\" type=\"Integer\">\n <esf:value>900</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.dhcpServer4.prefix\" type=\"Short\">\n <esf:value>24</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.dhcpServer4.passDns\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.dhcpServer4.rangeStart\" type=\"String\">\n <esf:value>192.168.4.100</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.dhcpServer4.maxLeaseTime\" type=\"Integer\">\n <esf:value>900</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.ip4.address\" type=\"String\">\n <esf:value>192.168.4.1</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.ip4.prefix\" type=\"Short\">\n <esf:value>24</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.ip4.gateway\" type=\"String\">\n <esf:value/>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.nat.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n </esf:properties>\n </esf:configuration>\n</esf:configurations>\n
"},{"location":"gateway-configuration/network-configuration/#configure-a-wireless-interface-as-access-point-with-dhcp-server-and-nat-enabled","title":"Configure a wireless interface as access point with DHCP server and NAT enabled","text":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n <esf:configuration pid=\"org.eclipse.kura.net.admin.NetworkConfigurationService\">\n <esf:properties>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.type\" type=\"String\">\n <esf:value>WIFI</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.ip4.status\" type=\"String\">\n <esf:value>netIPv4StatusEnabledLAN</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.ip4.gateway\" type=\"String\">\n <esf:value/>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.ip4.dnsServers\" type=\"String\">\n <esf:value/>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.ip4.prefix\" type=\"Short\">\n <esf:value>24</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.ip4.address\" type=\"String\">\n <esf:value>172.16.1.1</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.dhcpClient4.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.dhcpServer4.rangeStart\" type=\"String\">\n <esf:value>172.16.1.100</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.dhcpServer4.maxLeaseTime\" type=\"Integer\">\n <esf:value>900</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.dhcpServer4.defaultLeaseTime\" type=\"Integer\">\n <esf:value>900</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.dhcpServer4.rangeEnd\" type=\"String\">\n <esf:value>172.16.1.110</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.dhcpServer4.prefix\" type=\"Short\">\n <esf:value>24</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.dhcpServer4.enabled\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.dhcpServer4.passDns\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.nat.enabled\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.mode\" type=\"String\">\n <esf:value>MASTER</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.master.driver\" type=\"String\">\n <esf:value>nl80211</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"true\" name=\"net.interface.wlp1s0.config.wifi.master.passphrase\" type=\"Password\">\n <esf:value>ZW5hYmxlbWVwbGVhc2U=</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.master.ssid\" type=\"String\">\n <esf:value>kura_gateway_19</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.master.securityType\" type=\"String\">\n <esf:value>SECURITY_WPA2</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.master.mode\" type=\"String\">\n <esf:value>MASTER</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.master.channel\" type=\"String\">\n <esf:value>11</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.master.radioMode\" type=\"String\">\n <esf:value>RADIO_MODE_80211g</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.master.ignoreSSID\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.master.pairwiseCiphers\" type=\"String\">\n <esf:value>CCMP</esf:value>\n </esf:property>\n </esf:properties>\n </esf:configuration>\n</esf:configurations>\n
"},{"location":"gateway-configuration/network-configuration/#configure-a-wireless-interface-as-station-mode-with-dhcp-client-enabled","title":"Configure a wireless interface as station mode with DHCP client enabled","text":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n <esf:configuration pid=\"org.eclipse.kura.net.admin.NetworkConfigurationService\">\n <esf:properties>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.type\" type=\"String\">\n <esf:value>WIFI</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.ip4.status\" type=\"String\">\n <esf:value>netIPv4StatusEnabledLAN</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.ip4.dnsServers\" type=\"String\">\n <esf:value/>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.dhcpClient4.enabled\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.dhcpServer4.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.mode\" type=\"String\">\n <esf:value>INFRA</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.infra.ssid\" type=\"String\">\n <esf:value>MyWirelessNetwork</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.infra.bgscan\" type=\"String\">\n <esf:value/>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"true\" name=\"net.interface.wlp1s0.config.wifi.infra.passphrase\" type=\"Password\">\n <esf:value>MyPasswordBase64</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.infra.ignoreSSID\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.infra.mode\" type=\"String\">\n <esf:value>INFRA</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.infra.pingAccessPoint\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.infra.driver\" type=\"String\">\n <esf:value>nl80211</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.infra.securityType\" type=\"String\">\n <esf:value>SECURITY_WPA2</esf:value>\n </esf:property>\n </esf:properties>\n </esf:configuration>\n</esf:configurations>\n
"},{"location":"gateway-configuration/network-configuration/#enable-a-cellular-interface","title":"Enable a cellular interface","text":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n <esf:configuration pid=\"org.eclipse.kura.net.admin.NetworkConfigurationService\">\n <esf:properties> \n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.type\" type=\"String\">\n <esf:value>MODEM</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.ip4.status\" type=\"String\">\n <esf:value>netIPv4StatusEnabledWAN</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.ip4.dnsServers\" type=\"String\">\n <esf:value/>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.dhcpClient4.enabled\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.dhcpServer4.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.idle\" type=\"Integer\">\n <esf:value>95</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"true\" name=\"net.interface.1-1.config.password\" type=\"Password\">\n <esf:value/>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.pdpType\" type=\"String\">\n <esf:value>IP</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.ipAddress\" type=\"String\">\n <esf:value/>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.maxFail\" type=\"Integer\">\n <esf:value>5</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.authType\" type=\"String\">\n <esf:value>NONE</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.lcpEchoInterval\" type=\"Integer\">\n <esf:value>0</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.enabled\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.activeFilter\" type=\"String\">\n <esf:value>inbound</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.lcpEchoFailure\" type=\"Integer\">\n <esf:value>0</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.diversityEnabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.resetTimeout\" type=\"Integer\">\n <esf:value>5</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.gpsEnabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.persist\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.dialString\" type=\"String\">\n <esf:value>atd*99***2#</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.apn\" type=\"String\">\n <esf:value>web.omnitel.it</esf:value>\n </esf:property>\n </esf:properties>\n </esf:configuration>\n</esf:configurations>\n
"},{"location":"gateway-configuration/network-configuration/#create-a-vlan","title":"Create a VLAN","text":"<?xml version=\"1.0\" encoding=\"UTF-8\"?><esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n <esf:configuration pid=\"org.eclipse.kura.net.admin.NetworkConfigurationService\">\n <esf:properties>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interfaces\" type=\"String\">\n <esf:value>wlan0,lo,ens33,vlanFull,ens34</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.dhcpServer4.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.nat.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.dhcpClient4.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.type\" type=\"String\">\n <esf:value>VLAN</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.ip4.status\" type=\"String\">\n <esf:value>netIPv4StatusEnabledLAN</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.vlan.parent\" type=\"String\">\n <esf:value>ens33</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.vlan.id\" type=\"Integer\">\n <esf:value>41</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.vlan.flags\" type=\"Integer\">\n <esf:value>1</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.vlan.ingress\" type=\"String\">\n <esf:value>1:2,3:4</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.vlan.egress\" type=\"String\">\n <esf:value>5:6</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.ip4.address\" type=\"String\">\n <esf:value>192.168.41.100</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.ip4.prefix\" type=\"Short\">\n <esf:value>24</esf:value>\n </esf:property>\n </esf:properties>\n </esf:configuration>\n</esf:configurations>\n
"},{"location":"gateway-configuration/network-failover/","title":"Network Failover","text":"For devices configured to use NetworkManager, it is possible to configure multiple WAN interfaces and a basic network failover functionality.
As in the picture below, the Kura UI allows for multiple WAN interfaces to be defined. Each WAN interface can be configured with a WAN Priority. WAN Priority is used to determine which interface will be selected for primary WAN. In the case where the primary WAN interface loses connection, then the next highest priority interface is assigned.
Kura uses NetworkManager's implementation to achieve network failover (see NetworkManager). Lower values correspond to higher priority. Allowed values range from -1 to 2147483647. Value -1 means that the metric is chosen automatically based on the device type (see NetworkManager DBUS properties).
To observe changes to the applied configuration, use the following command on your device's shell:
route -n\n\nKernel IP routing table\nDestination Gateway Genmask Flags Metric Ref Use Iface\n0.0.0.0 192.168.2.1 0.0.0.0 UG 100 0 0 eth0\n172.16.1.0 0.0.0.0 255.255.255.0 U 600 0 0 wlan0\n172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0\n192.168.2.0 0.0.0.0 255.255.255.0 U 100 0 0 eth0\n
The metric
flag will correspond to the set WAN Priority. NetworkManager will always prioritize lower metric routes.
The NetworkManager failover mechanism can work at two different levels:
NetworkManager brings a network interface down when it detects the loss of its physical link. In such case, the next highest priority interface is selected as the main one.
When the connectivity check fails, NetworkManager penalizes the metric of that interface in the routing table. NetworkManager continues to perform connectivity checks over all the other interfaces. As soon as the connectivity is restored over a previously failing interface, the metric is also restored to the original value and the routing table goes back to the original state.
"},{"location":"gateway-configuration/network-failover/#configuring-the-connectivity-check","title":"Configuring the connectivity check","text":"The connectivity check is enabled by default in Kura and is configured to probe the connection to http://network-test.debian.org/nm
every 60 seconds. To set a specific URI and a different interval edit /etc/NetworkManager/conf.d/99kura-nm.conf
(reference NetworkManager):
[connectivity]\nuri=http://network-test.debian.org/nm\ninterval=60\nresponse=\"NetworkManager is online\"\n
The minimun interval is 60 seconds, if no interval is specified it defaults to 300 seconds.
The response should match what the URI is returning when probed. Some examples of web pages with NetworkManager responses:
URI Responsehttp://network-test.debian.org/nm
NetworkManager is online
https://fedoraproject.org/static/hotspot.txt
OK
http://nmcheck.gnome.org/check_network_status.txt
NetworkManager is online
https://www.pkgbuild.com/check_network_status.txt
NetworkManager is online
To disable the connectivity check feature:
[connectivity]
section from the configuration file; orinterval=0
; oruri
; oruri=
Each interface in the Network page contains inside its specific box the tab Hardware
: this collects the most significant information about the current state of the interface.
In this way the user can have a quick and complete view of what are the settings and physical specifications of a network interface.
These information are respectively:
UNMANAGED
, ACTIVATED
, FAILED
, UNKNOWN
.WIFI
or ETHERNET
These entries are filled only if the associated data is available. This means, for example, that no information will be shown under Current WLAN Channel
if the interface is of Ethernet type. Conversely, if the interface is Wifi type and no information is shown, it is possible that there has been some problem with the configuration or connection of the interface.
So this tab, could be also an intuitive way to check if the interface is working properly or not.
"},{"location":"gateway-configuration/network-threat-manager/","title":"Network Threat Manager","text":"Eclipse Kura provides a set of features to detect and prevent network attacks. The Security section in the Gateway Administration Console shows the Network Threat Manager tab where is it possible to activate these functions.
Warning
The Network Threat Manager tab is not available for the No Network version of Eclipse Kura.
"},{"location":"gateway-configuration/network-threat-manager/#flooding-protection","title":"Flooding protection","text":"The flooding protection function is used to prevent DDos (Distributed Denial-of-Service) attacks using the firewall. When enabled, the feature adds a set of firewall rules to the mangle table.
"},{"location":"gateway-configuration/network-threat-manager/#flooding-protection-for-ipv4","title":"Flooding protection for IPv4","text":"The following rules are added to the mangle table and they are implemented to block invalid or malicious network packets:
iptables -A prerouting-kura -m conntrack --ctstate INVALID -j DROP\niptables -A prerouting-kura -p tcp ! --syn -m conntrack --ctstate NEW -j DROP\niptables -A prerouting-kura -p tcp -m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags FIN,SYN FIN,SYN -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags SYN,RST SYN,RST -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags FIN,RST FIN,RST -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags FIN,ACK FIN -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags ACK,URG URG -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags ACK,FIN FIN -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags ACK,PSH PSH -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags ALL ALL -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags ALL NONE -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags ALL SYN,FIN,PSH,URG -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP\niptables -A prerouting-kura -p icmp -j DROP\niptables -A prerouting-kura -f -j DROP\n
To further filter the incoming TCP fragmented packets, specific system configuration files are configured. The flooding.protection.enabled property is used to enable the feature.
"},{"location":"gateway-configuration/network-threat-manager/#flooding-protection-for-ipv6","title":"Flooding protection for IPv6","text":"The same rules applied to the IPv4 are used for preventing attack on IPv6. In addition, some rules are implemented to drop specific IPv6 headers and limit the incoming ICMPv6 packets. Moreover, the incoming TCP fragmented packets are dropped configuring specific system files.
The following rules are applied to the mangle table:
ip6tables -A prerouting-kura -m conntrack --ctstate INVALID -j DROP\nip6tables -A prerouting-kura -p tcp ! --syn -m conntrack --ctstate NEW -j DROP\nip6tables -A prerouting-kura -p tcp -m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags FIN,SYN FIN,SYN -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags SYN,RST SYN,RST -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags FIN,RST FIN,RST -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags FIN,ACK FIN -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags ACK,URG URG -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags ACK,FIN FIN -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags ACK,PSH PSH -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags ALL ALL -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags ALL NONE -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags ALL SYN,FIN,PSH,URG -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP\nip6tables -A prerouting-kura -p ipv6-icmp -m ipv6-icmp --icmpv6-type 128 -j DROP\nip6tables -A prerouting-kura -p ipv6-icmp -m ipv6-icmp --icmpv6-type 129 -j DROP\nip6tables -A prerouting-kura -m ipv6header --header dst --soft -j DROP\nip6tables -A prerouting-kura -m ipv6header --header hop --soft -j DROP\nip6tables -A prerouting-kura -m ipv6header --header route --soft -j DROP\nip6tables -A prerouting-kura -m ipv6header --header frag --soft -j DROP\nip6tables -A prerouting-kura -m ipv6header --header auth --soft -j DROP\nip6tables -A prerouting-kura -m ipv6header --header esp --soft -j DROP\nip6tables -A prerouting-kura -m ipv6header --header none --soft -j DROP\nip6tables -A prerouting-kura -m rt --rt-type 0 -j DROP\nip6tables -A output-kura -m rt --rt-type 0 -j DROP\n
Also in this case, to enable the feature and add the rules to the firewall, the flooding.protection.enabled.ipv6 property has to be set to true. If the device doesn't support IPv6, this property is ignored.
Warning
To recover the device state when the IPv6 flooding protection feature is disabled, a reboot is required. So, to disable the feature, set the flooding.protection.enabled.ipv6 property to false tha reboot the device.
"},{"location":"gateway-configuration/ssl-configuration/","title":"SSL Configuration","text":"A SSL Service instance manages the configuration of the SSL connections. It uses the associated KeystoreService to access the trust certificates, private keys pairs needed to setup a SSL connection. It also enforces best practices that are not enabled by default in the Java VM, such as, enabling hostname verification, disabling the legacy SSL-2.0-compatible Client Hello, and disabling the Nagle algorithm.
The list of all available SSL Service instances is available in the SSL Configuration tab of the Security section, accessible only by the users with the corresponding permission.
By default, the framework creates a SSLManagerService instance with the org.eclipse.kura.ssl.SslManagerService
PID. This instance is generally used by all the core services of the framework.
A new SSL Service instance can be created using the New Button, by specifying the desired factory and the Service PID that will be associated with this new instance.
An instance of the default org.eclipse.kura.ssl.SslManagerService
factory has the following configuration parameters:
KeystoreService Target Filter - specifies, as an OSGi target filter, the pid of the KeystoreService used to manage the SSL key store (Required field).
Truststore Target Filter - specifies, as an OSGi target filter, the pid of the KeystoreService used to manage the SSL trust store. If the target service cannot be found, the service configured with the Keystore Target Filter parameter will be used as truststore.
ssl.default.protocol - defines the allowed SSL protocol.
ssl.hostname.verification - indicates whether hostname verification is enabled or disabled.
ssl.default.cipherSuites - defines the allowed cipher suites.
By selecting the Select available targets button, the user can associate the SSLManagerService instance with the corresponding KeystoreService instances available in the framework runtime.
"},{"location":"gateway-configuration/ssl-configuration/#server-ssl-certificate","title":"Server SSL Certificate","text":"The device requires a public key in its trust store in order to authenticate the broker and be able to setup an SSL connection. Kura is distributed with a pre-initialized SSL keystore that contains only some of the major Certification Authorities (CA) public keys.
If the broker uses a certificate signed by a different CA, or uses an auto-signed certificate, the system administrator must setup Kura with the correct certificates used to trust the remote cloud broker.
The inclusion of public certificates is accomplished with the Server SSL Certificate feature. To do so, the SSL Certificates form must be completed by providing a certificate or a certificates chain to be trusted and defining the alias used to register this new data in the device's trust store.
With this feature, when the device tries to instantiate an SSL connection with the broker, it receives the broker's public key chain. The SSL connection is secured only if the received chain is trusted. This connection can only happen if one of the certificates that compose the broker chain are available in the device's trust store.
When instantiating the device's trust store, the user decides whether to add a single certificate (leaf or CA certificate) or the full chain.
In the latter case, the chain should be provided by specifying the leaf certificate, followed by the CA certificate that is signing it, and so on, until the root CA is reached. An example of this scenario is depicted in the following image:
"},{"location":"gateway-configuration/ssl-configuration/#device-ssl-certificate-mutual-authentication","title":"Device SSL Certificate & Mutual Authentication","text":"Mutual authentication is a technique that allows authentication of the device that is connecting to the broker. The form available in Certificates List may be used to specify the keys needed to enable mutual authentication.
This authentication may be accomplished by specifying a couple of certificates (private and public keys) to be used by the client device to authenticate itself to the broker. This authentication is possible because the broker has the root CA certificate that has been used to sign the couple held by the device. In this way, the authenticity of the couple of certificates held by the device may be verified, and therefore, enable the two communicating parts (the broker and the device) to trust each other.
To enable mutual authentication, the user must complete the form with a well-formed key pair (public and private), and with an alias value that corresponds with the account name used to connect to the broker.
"},{"location":"gateway-configuration/ssl-configuration/#key-pair-generation","title":"Key Pair Generation","text":"The keys may be generated using specific software, such as OpenSSL or Keytool. This section describes how to use OpenSSL to generate a couple of private and public keys.
The private key may be created using the following command:
openssl genrsa -out certsDirectory/certs/certificate.key 1024\n
This command creates a new, 1024-bit private key in the specified path. This key is used to generate a Certificate Signing Request (CSR) file, which is used by a CA to authenticate the certificate's creator. A CSR file is created with OpenSSL using the following command:
openssl req -new -key certsDirectory/certs/certificate.key -out certsDirectory/crl/certificate.csr\n
If the user is creating their own certificate chain, the CSR file may be signed using a personal CA. This process may be accomplished using OpenSSL with the following command:
openssl ca -config certsDirectory/openssl.cnf -days 3650 -keyfile certsDirectory/ca/ca.key -cert certsDirectory/ca/ca.pem -out certsDirectory/certs/certificate.pem -infiles certsDirectory/crl/certificate.csr\n
The parameters are defined as follows:
-config: specifies the OpenSSL configuration file that must be used to sign the certificate.
-days: specifies how long the certificate is valid.
-keyfile and -cert: allow the specification of the CA that will sign the CSR file.
-out: identifies the location and the name of the signed certificate that will be created.
-infiles: identifies the location of the CSR file that has to be signed.
Tip
The private key may not be placed into the Kura Gateway Administration Console without a format conversion.
OpenSSL offers the following command to convert the input private key to a non-encrypted PKCS#8 format that may be processed by the Kura code:
openssl pkcs8 -topk8 -inform PEM -outform PEM -in inPrivateKey.key -out outKey.pem -nocrypt\n
"},{"location":"gateway-configuration/vlan-configuration/","title":"VLAN Configuration","text":"For devices running Kura installed using a Generic Profile, it is possible to configure multiple VLAN interfaces. Take a look at our installer profiles to know which are supported.
A VLAN, or Virtual Local Area Network, is a network segmentation technology that allows a single physical network to be logically divided into multiple isolated networks. These virtual networks operate as if they are independent, even though they share the same physical infrastructure. This is achieved via a VLAN ID, or VLAN tag, a numerical label added to network frames to identify the specific Virtual Local Area Network (VLAN) to which they belong. It's a critical component in VLAN technology, allowing network switches and routers to differentiate and route traffic within a VLAN. VLAN tags are added to the Ethernet frame's header, indicating which virtual network a data packet should be directed to when it traverses the physical network infrastructure. Therefore, VLANs must also be supported and configured on the network equipment a device is connected to.
A VLAN can be named freely, as long as it's 15 or less characters. A typical VLAN naming format is physicalInterfaceName
.vlanId
(eg. a vlan with id 100 on the interface eth0 would be named eth0.100).
This is achieved by NetworkManager by creating a virtual device bound to the underlying physical interface when Kura sets up a new VLAN connection.
"},{"location":"gateway-configuration/vlan-configuration/#vlan-configuration-via-kura-snapshot-upload","title":"VLAN Configuration via Kura Snapshot upload","text":"Currently, VLAN configuration is supported via uploading snapshot.xml fragments.
Warning
When creating a new VLAN be sure to include the net.interfaces
parameter, containing both the previously existing network interfaces, either virtual or physical, and the name of the new VLAN to be created.
The following example creates a VLAN with ID 40 over the ethernet interface ens33, naming it ens33.40
, using a predefined IP address, enabled for LAN.
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n <esf:configuration pid=\"org.eclipse.kura.net.admin.NetworkConfigurationService\">\n <esf:properties>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interfaces\" type=\"String\">\n <esf:value>lo,ens33,ens34,ens33.40</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.40.config.dhcpServer4.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.40.config.nat.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.40.config.dhcpClient4.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.40.type\" type=\"String\">\n <esf:value>VLAN</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.40.config.ip4.status\" type=\"String\">\n <esf:value>netIPv4StatusEnabledLAN</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.40.config.vlan.parent\" type=\"String\">\n <esf:value>ens33</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.40.config.vlan.id\" type=\"Integer\">\n <esf:value>40</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.40.config.ip4.address\" type=\"String\">\n <esf:value>10.0.55.37</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.40.config.ip4.prefix\" type=\"Short\">\n <esf:value>24</esf:value>\n </esf:property>\n </esf:properties>\n </esf:configuration>\n</esf:configurations>\n
"},{"location":"gateway-configuration/vlan-configuration/#complete-vlan-configuration-example","title":"Complete VLAN configuration example","text":"The following example creates a VLAN with ID 41 over the ethernet interface ens33, naming it ens33.41
, using a predefined IP address, enabled for WAN. This example also sets the 'flags' and 'traffic priority' optional parameters as described in Network Manager API documentation.
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n <esf:configuration pid=\"org.eclipse.kura.net.admin.NetworkConfigurationService\">\n <esf:properties>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interfaces\" type=\"String\">\n <esf:value>lo,ens33,ens34,ens33.41</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.dhcpServer4.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.nat.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.dhcpClient4.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.type\" type=\"String\">\n <esf:value>VLAN</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.ip4.gateway\" type=\"String\">\n <esf:value>192.168.41.254</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.ip4.status\" type=\"String\">\n <esf:value>netIPv4StatusEnabledWAN</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.ip4.dnsServers\" type=\"String\">\n <esf:value>8.8.8.8</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.vlan.parent\" type=\"String\">\n <esf:value>ens33</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.vlan.id\" type=\"Integer\">\n <esf:value>41</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.ip4.address\" type=\"String\">\n <esf:value>192.168.41.1</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.ip4.prefix\" type=\"Short\">\n <esf:value>24</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.vlan.flags\" type=\"Integer\">\n <esf:value>1</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.vlan.ingress\" type=\"String\">\n <esf:value>1:2,3:4</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.vlan.egress\" type=\"String\">\n <esf:value>5:6</esf:value>\n </esf:property>\n </esf:properties>\n </esf:configuration>\n</esf:configurations>\n
"},{"location":"gateway-configuration/vlan-configuration/#vlan-management","title":"VLAN Management","text":"Once a VLAN is created it can be managed via the Kura UI just like any other Ethernet interface.
Warning
Setting a VLAN status to \"Disabled\" deletes its configuration in NetworkManager and the related virtual interface from the system. Although it will is no longer be visible on the UI, all the configurations are left in Kura. Therefore the VLAN can be restored by setting the net.interface.<interface>.config.ip4.status
to netIPv4StatusEnabledLAN
or netIPv4StatusEnabledWAN
via snapshot upload, then resume configuration via UI.
As an example, the configuration to reactivate a disabled VLAN named ens33.40 would be as follows:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n <esf:configuration pid=\"org.eclipse.kura.net.admin.NetworkConfigurationService\">\n <esf:properties>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.40.config.ip4.status\" type=\"String\">\n <esf:value>netIPv4StatusEnabledLAN</esf:value>\n </esf:property>\n </esf:properties>\n </esf:configuration>\n</esf:configurations>\n
"},{"location":"gateway-configuration/web-console-configuration/","title":"Web Console Configuration","text":"The Web Console exposes a set of configuration parameters that can be used to increase the overall UI security. The Web Console configuration can be accessed in the Security section.
"},{"location":"gateway-configuration/web-console-configuration/#web-server-entry-point","title":"Web Server Entry Point","text":"This parameter allows to configure the relative path that the user will be redirected to when accessing http(s)://gateway-ip/. Note: this parameter does not change the Kura Web UI relative path, that is always /admin/console. The default value set is /admin/console
"},{"location":"gateway-configuration/web-console-configuration/#session-max-inactivity-interval","title":"Session max inactivity interval","text":"The session max inactivity interval in minutes. If no interaction with the Web UI is performed for the value of this parameter in minutes, a new login will be requested. The default value set is 15 minutes
"},{"location":"gateway-configuration/web-console-configuration/#access-banner-enabled","title":"Access Banner Enabled","text":"For security reasons, it may be needed to display to the user a banner that describes the intended system use before authenticating.
Once enabled and configured, the Kura Web UI will display a banner before every access attempt, as depicted in the image below.
"},{"location":"gateway-configuration/web-console-configuration/#password-management","title":"Password Management","text":"This section is related to the definition of required parameters that must be respected when defining a new password, for example when a user changes its password at first access.
"},{"location":"gateway-configuration/web-console-configuration/#minimum-password-length","title":"Minimum password length","text":"The minimum length to be enforced for new passwords. Set to 0 to disable. The default value set is 8 characters
"},{"location":"gateway-configuration/web-console-configuration/#require-digits-in-new-password","title":"Require digits in new password","text":"If set to true, new passwords will be accepted only if containing at least one digit. The default value is false
"},{"location":"gateway-configuration/web-console-configuration/#require-special-characters-in-new-password","title":"Require special characters in new password","text":"If set to true, new passwords will be accepted only if containing at least one non alphanumeric character The default value is false
"},{"location":"gateway-configuration/web-console-configuration/#require-uppercase-and-lowercase-characters-in-new-passwords","title":"Require uppercase and lowercase characters in new passwords","text":"If set to true, new passwords will be accepted only if containing both uppercase and lowercase alphanumeric characters. The default value is false
"},{"location":"gateway-configuration/web-console-configuration/#allowed-ports","title":"Allowed ports","text":"If set to a non empty list, Web Console access will be allowed only on the specified ports. If set to an empty list, access will be allowed on all ports. It is needed for the end user to make sure that the allowed ports are open in HttpService and Firewall configuration.
"},{"location":"gateway-configuration/web-console-configuration/#authentication-method-password-enabled","title":"Authentication Method \"Password\" Enabled","text":"Defines whether the \"Password\" authentication method is enabled or not. The default value is true
"},{"location":"gateway-configuration/web-console-configuration/#authentication-method-certificate-enabled","title":"Authentication Method \"Certificate\" Enabled","text":"Defines whether the \"Certificate\" authentication method is enabled or not The default value is true
"},{"location":"gateway-configuration/web-console-configuration/#sslmanagerservice-target-filter","title":"SslManagerService Target Filter","text":"It is possible to specify the SslManagerService containing the certificates truststore required to establish a new https connection, this is needed, for example, for fetching package descriptions from Eclipse Marketplace. The default target is the org.eclipse.kura.ssl.SslManagerService
"},{"location":"gateway-configuration/wifi-configuration-8021x/","title":"Wi-Fi 802.1x Configuration","text":"Enterprise Wi-Fi is currently only supported on gateways running our generic profiles. The following is a list of currently supported 802.1x authentication methods.
WPA2/WPA3-Enterprise
TTLS
MSCHAPV2
Identity (Username)
Password
The configuration should look like the following:
"},{"location":"gateway-configuration/wifi-configuration-8021x/#peap-mschapv2","title":"PEAP-MSCHAPv2","text":"WPA2/WPA3-Enterprise
PEAP
MSCHAPV2
Identity (Username)
Password
The configuration should look like the following:
"},{"location":"gateway-configuration/wifi-configuration-8021x/#eap-tls","title":"EAP-TLS","text":"To connect via EAP-TLS you will need the following items in unencrypted PEM format:
Security
under the System
tab.Keystore Configuration
add a new keystore, and keep note of the name. Certificate List
and create a new Certificate. Insert the PEM and Apply, keep note of the name. add
and create a new Private Key. Insert both the certificates in the PEM in the dialogue and press apply. keep note of the name. WPA2/WPA3-Enterprise
. TLS
.Identity (Username)
.Keystore Pid
to the name of the keystore created above.Certificate Authority Certificate (CA-Cert)
to the name of the certificate created above.Client Private Key
to the name of the Private Key created above.When completed the Wi-Fi configuration should look like the following:
"},{"location":"gateway-configuration/wifi-configuration/","title":"Wi-Fi Configuration","text":"From a configuration standpoint, the Wi-Fi interface (e.g., wlan0) may be viewed as an extension of Ethernet. In addition to the TCP/IP and DHCP & NAT configuration tabs, it has the Wireless tab that allows for the configuration of wireless settings. These configuration options are described below.
Warning
Before using wifi make sure that you have correctly set the Regulatory Domain on the gateway. You can check the current configuration using the iw reg get
command. To set the Regulatory Domain please refer to the specific section in the Gateway Configurations.
The Wireless tab contains the following configuration parameters:
Wireless Mode: defines the mode of operation.
Network Name: specifies the Service Set Identifier (SSID).
Radio Mode: defines 802.11 mode.
Wireless Security: sets the security protocol for the wireless network.
Wireless Password: sets the password for the wireless network.
Verify Password: sets the password verification field.
Pairwise Ciphers: lists accepted pairwise (unicast) ciphers for WPA/WPA2.
Group Ciphers: lists accepted group (broadcast/multicast) ciphers for WPA/WPA2.
Bgscan Module: requests background scans for the purpose of roaming within an ESS (i.e., within a single network block with all the APs using the same SSID).
Bgscan Signal Strength Threshold: defines a threshold (in dBm) that determines which one of the following two parameters (i.e., Short Interval or Long Interval) will be effective.
Bgscan Short Interval: defines the interval between background scans (in seconds) if the actual signal level of the currently connected access point is worse than signal_strength.
Bgscan Long Interval: defines the interval between background scans (in seconds) if the actual signal level of the currently connected access point is better than signal_strength.
Ping Access Point & renew DHCP lease if not reachable: enables pinging the access point after connection is established.
Ignore Broadcast SSID: operates as follows if set to true:
Channels table: allows the selection of desired channel frequencies. The availability of the desired frequency is subject to the Regdom set on the device. For a list of limitations in different countries you can consult the following page: List of WLAN channels. Channels marked as No Irradiation and Radar Detection can be used only if DFS (Dynamic Frequency Selection) is supported by the Wi-Fi chip.
In addition to the options described above, the Wireless configuration display provides two buttons that help to configure Wi-Fi in the Station mode. These buttons are described below.
Access Point Scan: clicking this button triggers access point scan operations. Upon a successful scan, a table containing access points within range is presented. This table contains the following information:
If you select one of these access points, respective wireless controls (i.e., Network Name, Wireless Security, and Channel) are filled with information obtained during the scan operation.
Password Verification: clicking this button triggers password verification before a full connection is established.
Generic Profiles Access Point Scan Issue
Due to a limitation in our current implementation of Access Point scanning in the generic profiles, a scan triggered while the device Wireless Mode is set as Access Point will result in it reporting itself as the only reachable Access Point.
To retrieve the actual list of nearby Access Points, set your device in Station Mode with a temporary configuration and trigger the scan again.
"},{"location":"gateway-configuration/wifi-configuration/#wi-fi-linux-configuration","title":"Wi-Fi Linux Configuration","text":"This section describes the changes applied by Kura at the Linux networking configuration. Please read the following note before proceeding with manual changes of the Linux networking configuration.
Warning
It is NOT recommended performing manual editing of the Linux networking configuration files when the gateway configuration is being managed through Kura. While Linux may correctly accept manual changes, Kura may not be able to interpret the new configuration resulting in an inconsistent state.
When the Wi-Fi configuration for the Access Point mode is submitted, Kura generates the /etc/hostapd.conf
file and launches the hostapd program as shown below.
hostapd:B /etc/hostapd.conf\n
# /etc/hostapd/hostapd.conf\n\ninterface=wlan0\n\ndriver=nl80211\n\n# SSID to use. This will be the \"name\" of the accesspoint\nssid=kura_gateway_00:E0:C7:09:35:D8\n\n# basic operational settings\nhw_mode=g\n\nwme_enabled=0\nieee80211n=0\n\nchannel=1\n\n# Logging and debugging settings: more of this in original config file\nlogger_syslog=-1\nlogger_syslog_level=2\nlogger_stdout=-1\nlogger_stdout_level=2\ndump_file=/tmp/hostapd.dump\n\n# WPA settings. We'll use stronger WPA2\n# bit0 = WPA\n# bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled)\nwpa=2\n\n# Preshared key of between 8-63 ASCII characters.\n# If you define the key in here, make sure that the file is not readable\n# by anyone but root. Alternatively you can use a separate file for the\n# key; see original hostapd.conf for more information.\nwpa_passphrase=testKEYS\n\n# Key management algorithm. In this case, a simple pre-shared key (PSK)\nwpa_key_mgmt=WPA-PSK\n\n# The cipher suite to use. We want to use stronger CCMP cipher.\nwpa_pairwise=CCMP\n\n# Change the broadcasted/multicasted keys after this many seconds.\nwpa_group_rekey=600\n\n# Change the master key after this many seconds. Master key is used as a basis\n# (source) for the encryption keys.\nwpa_gmk_rekey=86400\n\n# Send empty SSID in beacons and ignore probe request frames that do not\n# specify full SSID, i.e., require stations to know SSID.\n# default: disabled (0)\n# 1 = send empty (length=0) SSID in beacon and ignore probe request for\n# broadcast SSID\n# 2 = clear SSID (ASCII 0), but keep the original length (this may be required\n# with some clients that do not support empty SSID) and ignore probe\n# requests for broadcast SSID\nignore_broadcast_ssid=0\n
When the Wi-Fi configuration for the Station mode is submitted, Kura generates the /etc/wpa_supplicant.conf
file and launches the wpa_supplicant
program as shown below.
wpa_supplicant:B:D nl80211:i wlan0:c /etc/wpa_supplicant.conf\n
# /etc/wpa_supplicant.conf\n# allow frontend (e.g., wpa_cli) to be used by all users in 'wheel' group\nctrl_interface=/var/run/wpa_supplicant\nctrl_interface_group=wheel\n\n# home network; allow all valid ciphers\nnetwork={\n mode=0\n ssid=\"Eurotech-INC\"\n scan_ssid=1\n key_mgmt=WPA-PSK\n psk=\"WG4t3101\"\n proto=RSN\n pairwise=CCMP TKIP\n group=CCMP TKIP\n scan_freq=2412\n bgscan=\"\"\n}\n
"},{"location":"getting-started/docker-quick-start/","title":"Docker Quick Start","text":""},{"location":"getting-started/docker-quick-start/#installation","title":"Installation","text":"Eclipse Kura is also available as a Docker container available in Docker Hub.
To download and run, use the following command:
docker run -d -p 443:443 -t eclipse/kura\n
This command will start Kura in background and the Kura Web Ui will be available through port 443.
Once the image is started you can navigate your browser to https://localhost and log in using the credentials admin : admin
.
Following, a set of useful Docker command that can be used to list and manage Docker containers. For more details on Docker commands, please reference the official Docker documentation
"},{"location":"getting-started/docker-quick-start/#list-docker-images","title":"List Docker Images","text":"To list all the installed Docker images run:
docker images\n
"},{"location":"getting-started/docker-quick-start/#list-running-docker-containers","title":"List Running Docker Containers","text":"To list all the available instances (both running and powered off) run:
docker ps -a\n
"},{"location":"getting-started/docker-quick-start/#startstop-a-docker-container","title":"Start/Stop a Docker Container","text":"docker stop <container id>\ndocker start <container id>\n
where <container id>
is the instance identification number.
Kura is provided using a DEB Linux package. Visit the Kura download page to find the correct installation file for the target system.
"},{"location":"getting-started/install-kura/#installer-types","title":"Installer types","text":"Several installers can be found on such page, and they fall into one of the following categories:
kura-5.5.0_generic-arm32_installer.deb
; andkura_5.5.0_nvidia-jetson-nano-nn_installer.deb
Profiles of types (1) and (2) ship a Kura version with networking functionalities. In particular, the installers of kind (1) use Kura Networking for leveraging network interface configurations and are made for a specific device.
Installers of type (2) can be installed on targets with NetworkManager; a commonly available tool for managing Linux networking. Kura leverages this tool for networking functionalities. Refer to the Generic installers section for further information.
Installers of type (3) with the suffix nn
are No Networking profiles that do not bundle the Kura Network Manager: all the network configurations need to be done outside of Kura. Functionalities missing in NN profiles compared to the full Kura profiles:
Kura can be installed using the generic profiles:
kura-<kura-version>_generic-<arch>_installer.deb/rpm\n
where <arch>
is one of the supported architectures: x86_64, arm32, and arm64. A generic Kura profile can work on systems that have available the dependencies listed in the Kura dependencies section, and that have at least one physical ethernet interface.
Eclipse Kura's Generic profile incorporates an adaptive Heap Memory allocation system during installation. The allocation follows a formula based on your gateway's available memory. If your gateway has less than 1024MB of RAM, Kura will set -Xms and -Xmx to 256MB. For gateways with more than 1024MB, one quarter of the total RAM will be assigned to -Xms and -Xmx.
"},{"location":"getting-started/install-kura/#initial-network-configuration","title":"Initial network configuration","text":"During the installation of Eclipse Kura with network management support, the initial network configuration will be generated dynamically. The existing wired and wireless network interface names are detected and sorted in ascending lexicographic order at the installation.
If only one ethernet interface is detected (e.g. eth0
), it will be configured as follows:
eth0
) - Status: Enabled for WAN
- Configure: Using DHCP
If multiple ethernet interfaces are detected, instead, the first two interfaces will be configured as presented in the table below. The other ethernet interfaces will be disabled.
Interface Configuration First Ethernet interface (e.g.eth0
) - Status: Enabled for LAN
- Configure: Manually
- IP address: 172.16.0.1
- Router Mode: DHCP and NAT
Second Ethernet interface (e.g. eth1
) - Status: Enabled for WAN
- Configure: Using DHCP
Finally, if a wireless interface (e.g. wlan0
) is detected, it will configured as shown below. The other wireless interfaces will be disabled.
wlan0
) - Status: Enabled for LAN
- Configure: Manually
- IP address: 172.16.1.1
- Passphrase: testKEYS
- Router Mode: DHCP and NAT
For example, if the system contains the following interfaces: wlp2s0
, wlp3s0
, enp3s0
, eno1
, ens2
; then eno1
will be enabled for LAN with a DHCP server, enp3s0
will be enabled for WAN in DHCP client mode, wlp2s0
will be configured as an AP, and all other network interfaces will be disabled.
Warning
On systems that do not use systemd's predictable interface naming scheme (see Freedesktop reference) the primary network interface name might change whenever a re-enumeration is triggered (for example, after a reboot or after plugging in an external network adapter).
The advice is to install Kura on systems that use a reliable naming convention for network interfaces.
Systemd consistent network interface naming assigns the name prefix based on the physical location of the device, see Understanding the Predictable Network Interface Device Names for further reference.
"},{"location":"getting-started/install-kura/#initial-firewall-configuration","title":"Initial firewall configuration","text":"Similarly to the initial network configuration, the initial firewall setup is adapted based on the network interface detected on the system. In case of multiple ethernet and wireless interfaces, the configuration will be as shown in the screenshot below.
If the wireless interface is not present, the firewall entries for the wlan0
are dropped.
Please note that installing Eclipse Kura with network configuration support will replace the current network and firewall configuration with the one shown above.
"},{"location":"getting-started/install-kura/#other-kura-services","title":"Other Kura services","text":"Kura generic profiles do not contain gateway specific customizations, this implies that the values of some configuration parameters may be incorrect and/or missing and must be manually filled after installation. For example the user might want to:
/opt/eclipse/kura/framework/jdk.dio.properties
with the correct GPIO mappings. By default this file is empty.To have all the Kura features working, the following dependencies are required:
setserial
, zip
, gzip
, unzip
, procps
, usbutils
, socat
, gawk
, sed
, inetutils-telnet
.polkit
or policykit-1
, ssh
or openssh
, openssl
, busybox
, openvpn
.bluez
or bluez5
, bluez-hcidump
or bluez5-noinst-tools
.ntpdate
, chrony
, chronyc
, cron
or cronie
.network-manager
or networkmanager
, bind9
or bind
, dnsmasq
or isc-dhcp-server
or (dhcp-server
and dhcp-client
), iw
, iptables
, modemmanager
, hostapd
, wpa-supplicant
, ppp
, iproute2
.logrotate
.gpsd
.python3
.openjdk-17-jre-headless
or temurin-17-jdk
or openjdk-8-jre-headless
or temurin-8-jdk
.dos2unix
Kura generic has been tested on the following devices and provides full configuration of all the available interfaces and GPIO mappings.
Device Architecture OS Raspberry Pi 3/4 arm32 Raspbian \"Bookworm\" Raspberry Pi 3/4 arm64 Ubuntu 20.04 Intel Up\u00b2 x86_64 Ubuntu 20.04 NVIDIA Jetson Nano\u2122 arm64 Ubuntu 20.04Check out the quick start guides for the detailed installation steps and set-up procedures:
This section provides Eclipse Kura\u2122 quick installation procedures for the Intel Up\u00b2 and the Kura development environment.
Warning
This quickstart will install the version of Kura with the administrative web UI and network configuration support but not CAN bus support. For more information on this please visit the Eclipse Kura download page
This quickstart has been tested using the latest Ubuntu 20.04.3 LTS Live Server for amd64 architecture flashed on the SD card with balenaEtcher.
A complete guide on how to install Ubuntu on the Intel Up\u00b2 can be found here.
It is important, in order to access the HAT, Bluetooth, Wifi functionality, to follow the relative steps provided in the complete guide. Make sure to assign the right execute permissions to kurad
user created by the installer as described here.
Note
It is highly recommended to install the custom Intel kernel provided in the guide.
"},{"location":"getting-started/intel-up-2-quick-start/#eclipse-kuratm-installation","title":"Eclipse Kura\u2122 Installation","text":"To install Kura with its dependencies on the Intel Up\u00b2, perform the following steps:
Boot the Intel Up\u00b2 with the Ubuntu Image 20.04.3.
Make sure your device is connected to internet.
Upgrade the system:
sudo apt update\n
sudo apt upgrade\n
Tip
Optional: Since version 5.3.0 Kura also supports Eclipse Temurin\u2122 as an alternative JVM. To install it you need to perform these additional steps:
sudo apt-get install -y wget apt-transport-https gnupg\n
sudo wget -O - https://packages.adoptium.net/artifactory/api/gpg/key/public | sudo apt-key add -\n
sudo echo \"deb https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main\" | sudo tee /etc/apt/sources.list.d/adoptium.list\n
sudo apt-get update\n
sudo apt-get install temurin-17-jdk\n
Download the Kura package with:
wget http://download.eclipse.org/kura/releases/<version>/kura_<version>_intel-up2-ubuntu-20_installer.deb\n
Note: replace <version>
in the URL above with the version number of the latest release (e.g. 5.2.0).
Install Kura with:
apt-get install./ kura_<version>_intel-up2-ubuntu-20_installer.deb\n
Set the right Wi-Fi regulatory domain based on your current world region editing the /etc/default/crda
and adding the ISO 3166-1 alpha-2 code of your region.
Reboot the Intel Up\u00b2 with:
sudo reboot\n
Kura starts on the target platform after reboot.
Kura setups a local web ui that is available using a browser via:
https://<device-ip>\n
The browser will prompt the user to accept the connection to an endpoint with an untrusted certificate:
Once trusted the source, the user will be redirected to a login page where the default username is:
admin\n
and the default password is:
admin\n
This section provides Eclipse Kura\u2122 quick installation procedures for the NVIDIA Jetson Nano\u2122.
Warning
This quickstart will install the version of Kura with the administrative web UI and network configuration support but not CAN bus support. For more information on this please visit the Eclipse Kura download page
This quickstart has been tested using the latest Ubuntu 18.04 LTS image provided by NVIDIA here and burned on a SD card with Etcher.
The official images can be found on the Jetson Nano Developer Kit Getting Starteg Guide. Further information on the Ubuntu installation for the NVIDIA Jetson Nano\u2122 can be found here.
"},{"location":"getting-started/nvidia-jetson-nano-quick-start/#eclipse-kuratm-installation","title":"Eclipse Kura\u2122 Installation","text":"To install Eclipse Kura with its dependencies on the NVIDIA Jetson Nano\u2122, perform the following steps:
Boot the NVIDIA Jetson Nano\u2122 with the latest\u00a0Jetson Nano Developer Kit SD Card image.
Make sure your device is connected to internet. By default, eth0
lan network interface is configured in DHCP mode.
Upgrade the system:
sudo apt update\n
sudo apt upgrade\n
Tip
Optional: Since version 5.3.0 Kura also supports Eclipse Temurin\u2122 as an alternative JVM. To install it you need to perform these additional steps:
sudo apt-get install -y wget apt-transport-https gnupg\n
sudo wget -O - https://packages.adoptium.net/artifactory/api/gpg/key/public | sudo apt-key add -\n
sudo echo \"deb https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main\" | sudo tee /etc/apt/sources.list.d/adoptium.list\n
sudo apt-get update\n
sudo apt-get install temurin-17-jdk\n
Download the Kura package with:
wget http://download.eclipse.org/kura/releases/<version>/kura_<version>_nvidia-jetson-nano_installer.deb\n
Note: replace <version>
in the URL above with the version number of the latest release (e.g. 5.2.0).
Install Kura with:
sudo apt install ./kura_<version>_nvidia-jetson-nano_installer.deb\n
All the required dependencies will be downloaded and installed.
Reboot the NVIDIA Jetson Nano\u2122 with:
sudo reboot\n
Kura starts on the target platform after reboot.
Kura setups a local web ui that is available using a browser via:
https://<device-ip>\n
The browser will prompt the user to accept the connection to an endpoint with an untrusted certificate:
Once trusted the source, the user will be redirected to a login page where the following credentianls: username: admin
password: admin
This section provides Eclipse Kura\u2122 quick installation procedures for the Raspberry Pi and the Kura development environment.
Warning
This quickstart will install the version of Kura with the administrative web UI and network configuration support but not CAN bus support. For more information on this please visit the Eclipse Kura download page
This quickstart has been tested using the latest Raspberry Pi OS 32 and 64 bits images which are available for download through the official Raspberry Pi foundation site and the Raspberry Pi Imager.
Warning
Recent versions of Raspberry Pi OS 32 bit on Raspberry PI 4 will use by default a 64 bit kernel with a 32 bit userspace. This can cause issues to applications that use the result of uname -m
to decide which native libraries to load (see https://github.com/raspberrypi/firmware/issues/1795). This currently affects for example the Kura SQLite database connector. It should be possible to solve by switching to the 32 bit kernel setting arm_64bit=0
in /boot/config.txt
and restarting the device.
For additional details on OS compatibility refer to the Kura\u2122 release notes.
"},{"location":"getting-started/raspberry-pi-raspberryos-quick-start/#enable-ssh-access","title":"Enable SSH Access","text":"The ssh server is disabled by default on Raspbian images released after November 2016, in order to enable it follow the instructions available here.
If you're using the Raspberry Pi Imager you can directly enable SSH before writing the operating system into the SD card by clicking on the \"setting\" icon.
"},{"location":"getting-started/raspberry-pi-raspberryos-quick-start/#eclipse-kuratm-installation","title":"Eclipse Kura\u2122 Installation","text":"To install Eclipse Kura with its dependencies on the Raspberry Pi, perform the following steps:
Boot the Raspberry Pi with the latest\u00a0Raspbian image (starting from release 5.1.0 Kura is tested with Raspbian 11).
Make sure your device is connected to the internet. The best installation experience can be obtained when the device is cabled to the local network and the Internet. By default, the Raspberry Pi OS configures the ethernet interface eth0
in DHCP mode.
Upgrade the system:
sudo apt update\n
sudo apt upgrade\n
Tip
Optional: Since version 5.3.0 Kura also supports Eclipse Temurin\u2122 as an alternative JVM. To install it you need to perform these additional steps:
sudo apt-get install -y wget apt-transport-https gnupg\n
sudo wget -O - https://packages.adoptium.net/artifactory/api/gpg/key/public | sudo apt-key add -\n
sudo echo \"deb https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main\" | sudo tee /etc/apt/sources.list.d/adoptium.list\n
sudo apt-get update\n
sudo apt-get install temurin-17-jdk\n
Download the Kura package with:
wget http://download.eclipse.org/kura/releases/<version>/kura-<kura-version>_generic-<arch>_installer.deb\n
Note: replace <version>
in the URL above with the version number of the latest release (e.g. 5.5.0) and <arch>
with your device architecture
Install Kura with:\u00a0
sudo apt-get install ./kura-<kura-version>_generic-<arch>_installer.deb\n
For a correct configuration of the Wlan interface, it is necessary to set the Locale and the WLAN Country through the raspi-config
command:
sudo raspi-config\n
From the raspi-config main menu select Localisation Options
:
Then modify the Locale and WLAN Country with with the proper settings for your location. For example, an user located in Italy could set the values as the ones in the table:
Setting Value L1 Locale it_IT.UTF-8 UTF-8 L4 WLAN Country IT Italy(Optional) To correctly use the GPIO pins, the user is asked to update the jdk.dio.properties
file with the proper configuration, based on its own device.
This is required since the sysfs
interface has been deprecated, and some OS distribution may have already suppressed it. Moreover, the kernel complains if a static base number is assigned to a GPIO controller: indeed, when it assigns the numbers automatically, it usually starts from 511. More information can be found here.
In order to set the correct configuration the user can perform the following steps:
cat /sys/kernel/debug/gpio
, looking for entries similar to gpio-ABC (GPIxx)
: from this information it is possible to retrieve which number the GPIO controller was assigned to by the OS (in this case the GPIO controller number xx
is assigned with the number ABC
). The image below represent an example of this file/opt/eclipse/kura/framework/jdk.dio.properties
with the number and controllers found in the previous step:573 = deviceType: gpio.GPIOPin, pinNumber:573, name:GPI02\n574 = deviceType: gpio.GPIOPin, pinNumber:574, name:GPIO3\n575 = deviceType: gpio.GPIOPin, pinNumber:575, name:GPIO4\n576 = deviceType: gpio.GPIOPin, pinNumber:576, name:GPIO5\n577 = deviceType: gpio.GPIOPin, pinNumber:577, name:GPIO6\n578 = deviceType: gpio.GPIOPin, pinNumber:578, name:GPIO7\n579 = deviceType: gpio.GPIOPin, pinNumber:579, name:GPIO8\n580 = deviceType: gpio.GPIOPin, pinNumber:580, name:GPIO9\n581 = deviceType: gpio.GPIOPin, pinNumber:581, name:GPIO10\n582 = deviceType: gpio.GPIOPin, pinNumber:582, name:GPIO11\n583 = deviceType: gpio.GPIOPin, pinNumber:583, name:GPIO12\n584 = deviceType: gpio.GPIOPin, pinNumber:584, name:GPIO13\n585 = deviceType: gpio.GPIOPin, pinNumber:585, name:GPIO14\n586 = deviceType: gpio.GPIOPin, pinNumber:586, name:GPIO15\n587 = deviceType: gpio.GPIOPin, pinNumber:587, name:GPIO16\n588 = deviceType: gpio.GPIOPin, pinNumber:588, name:GPIO17\n589 = deviceType: gpio.GPIOPin, pinNumber:589, name:GPIO18\n590 = deviceType: gpio.GPIOPin, pinNumber:590, name:GPIO19\n591 = deviceType: gpio.GPIOPin, pinNumber:591, name:GPIO20\n592 = deviceType: gpio.GPIOPin, pinNumber:592, name:GPIO21\n593 = deviceType: gpio.GPIOPin, pinNumber:593, name:GPIO22\n594 = deviceType: gpio.GPIOPin, pinNumber:594, name:GPIO23\n595 = deviceType: gpio.GPIOPin, pinNumber:595, name:GPIO24\n596 = deviceType: gpio.GPIOPin, pinNumber:596, name:GPIO25\n597 = deviceType: gpio.GPIOPin, pinNumber:597, name:GPIO26\n598 = deviceType: gpio.GPIOPin, pinNumber:598, name:GPIO27\n\ngpio.GPIOPin = initValue:0, deviceNumber:0, direction:3, mode:-1, trigger:3\nuart.UART = baudRate:19200, parity:0, dataBits:8, stopBits:1, flowControl:0\n
You can also check your GPIO device configuration executing the command pinout
Reboot the Raspberry Pi with:
sudo reboot\n
Kura starts on the target platform after reboot.
Kura setups a local web ui that is available using a browser via:
https://<device-ip>\n
The browser will prompt the user to accept the connection to an endpoint with an untrusted certificate:
Once trusted the source, the user will be redirected to a login page where the following credentials: username: admin
password: admin
This section provides Eclipse Kura\u2122 quick installation procedures for the Raspberry Pi.
Warning
This quickstart will install the version of Kura with the administrative web UI and network configuration support but not CAN bus support. For more information on this please visit the Eclipse Kura download page
This quickstart has been tested using the latest Ubuntu 20.04.3 LTS Live Server for arm64 architecture flashed on the SD card through Raspberry Pi Imager.
The official images can be also found on the Project Page. Further information on the Ubuntu installation for Raspberry Pi can be found here.
Warning
Please note that, at the time of this writing, only 64 bit OS image is supported.
"},{"location":"getting-started/raspberry-pi-ubuntu-20-quick-start/#enable-ssh-access","title":"Enable SSH Access","text":"On Ubuntu 20.04.3 the ssh access is enabled only for the standard ubuntu user. If you desire to remote login as root user, edit the file /etc/ssh/sshd_config
(using the root permission) adding the line PermitRootLogin yes
To install Eclipse Kura with its dependencies on the Raspberry Pi, perform the following steps:
Boot the Raspberry Pi with the latest\u00a0Ubuntu 20.04.3 LTS Server image.
Make sure your device is connected to internet. By default, eth0
lan network interface is configured in DHCP mode.
Upgrade the system:
sudo apt update\n
sudo apt upgrade\n
Tip
Optional: Since version 5.3.0 Kura also supports Eclipse Temurin\u2122 as an alternative JVM. To install it you need to perform these additional steps:
sudo apt-get install -y wget apt-transport-https gnupg\n
sudo wget -O - https://packages.adoptium.net/artifactory/api/gpg/key/public | sudo apt-key add -\n
sudo echo \"deb https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main\" | sudo tee /etc/apt/sources.list.d/adoptium.list\n
sudo apt-get update\n
sudo apt-get install temurin-17-jdk\n
Download the Kura package with:
wget http://download.eclipse.org/kura/releases/<version>/kura-<kura-version>_generic-<arch>_installer.deb\n
Note: replace <version>
in the URL above with the version number of the latest release (e.g. 5.5.0) and <arch>
with your device architecture
Install Kura with:
sudo apt install ./kura-<kura-version>_generic-<arch>_installer.deb\n
All the required dependencies will be downloaded and installed.
Set the right Wi-Fi regulatory domain based on your current world region editing the /etc/default/crda
and adding the ISO 3166-1 alpha-2 code of your region.
(Optional) Configure the GPIO replacing the content of the file /opt/eclise/kura/framework/jdk.dio.properties
with the following text:
0 = deviceType: gpio.GPIOPin, pinNumber:0, name:GPIO0\n1 = deviceType: gpio.GPIOPin, pinNumber:1, name:GPIO1\n2 = deviceType: gpio.GPIOPin, pinNumber:2, name:GPI02\n3 = deviceType: gpio.GPIOPin, pinNumber:3, name:GPIO3\n4 = deviceType: gpio.GPIOPin, pinNumber:4, name:GPIO4\n5 = deviceType: gpio.GPIOPin, pinNumber:5, name:GPIO5\n6 = deviceType: gpio.GPIOPin, pinNumber:6, name:GPIO6\n7 = deviceType: gpio.GPIOPin, pinNumber:7, name:GPIO7\n8 = deviceType: gpio.GPIOPin, pinNumber:8, name:GPIO8\n9 = deviceType: gpio.GPIOPin, pinNumber:9, name:GPIO9\n10 = deviceType: gpio.GPIOPin, pinNumber:10, name:GPIO10\n11 = deviceType: gpio.GPIOPin, pinNumber:11, name:GPIO11\n12 = deviceType: gpio.GPIOPin, pinNumber:12, name:GPIO12\n13 = deviceType: gpio.GPIOPin, pinNumber:13, name:GPIO13\n14 = deviceType: gpio.GPIOPin, pinNumber:14, name:GPIO14\n15 = deviceType: gpio.GPIOPin, pinNumber:14, name:GPIO15\n16 = deviceType: gpio.GPIOPin, pinNumber:16, name:GPIO16\n17 = deviceType: gpio.GPIOPin, pinNumber:17, name:GPIO17\n18 = deviceType: gpio.GPIOPin, pinNumber:18, name:GPIO18\n19 = deviceType: gpio.GPIOPin, pinNumber:19, name:GPIO19\n20 = deviceType: gpio.GPIOPin, pinNumber:20, name:GPIO20\n21 = deviceType: gpio.GPIOPin, pinNumber:21, name:GPIO21\n22 = deviceType: gpio.GPIOPin, pinNumber:22, name:GPIO22\n23 = deviceType: gpio.GPIOPin, pinNumber:23, name:GPIO23\n24 = deviceType: gpio.GPIOPin, pinNumber:24, name:GPIO24\n25 = deviceType: gpio.GPIOPin, pinNumber:25, name:GPIO25\n26 = deviceType: gpio.GPIOPin, pinNumber:26, name:GPIO26\n27 = deviceType: gpio.GPIOPin, pinNumber:27, name:GPIO27\n\ngpio.GPIOPin = initValue:0, deviceNumber:0, direction:3, mode:-1, trigger:3\nuart.UART = baudRate:19200, parity:0, dataBits:8, stopBits:1, flowControl:0\n
Reboot the Raspberry Pi with:
sudo reboot\n
Kura starts on the target platform after reboot.
Kura setups a local web ui that is available using a browser via:
https://<device-ip>\n
The browser will prompt the user to accept the connection to an endpoint with a self signed certificate, select Accept the risk and continue
:
Once trusted the source, the user will be redirected to a login page where the following credentianls: username: admin
password: admin
This section provides a simple example of how to create an OSGi bundle that implements the ConfigurableComponent interface in Kura. This bundle will interact with the Kura ConfigurationService via the ConfigurableComponent interface. It also uses the MQTT services in Kura to connect to the Cloud, which allows for a local configuration mechanism using a Web user-interface (UI). In this example, you will learn how to perform the following functions:
Create a plugin project
Implement the ConfigurableComponent interface
Use the Kura web UI to modify the bundle\u2019s configuration
Export a single OSGi bundle (plug-in)
Requires Kura development environment set-up (Setting up Kura Development Environment)
Implements the use of Kura web user-interface (UI)
In Eclipse, create a new Plug-in project by selecting File | New | Project. Select Plug-in Development | Plug-in Project and click Next.
Your screen should display the New Plug-in Project dialog box as shown in the following screen capture. Enter your project a name, such as \u201corg.eclipse.kura.example.configurable\u201d. Under Target Platform, ensure that the an OSGi framework option button is selected and set to standard as shown below. You can also (optionally) add projects to a working set. To continue, click Next.
In the next New Plug-in Project menu (shown below), change the Name field to something more descriptive, such as \u201cConfigurable Component Example.\u201d Make sure that the Execution Environment list is set to match the JVM version running on the target device (JavaSE-1.6 or JavaSE-1.7). To determine the JVM version running on the target device, log in to its administrative console and enter the command
java \u2013version
Also, uncheck the Generate an activator, a Java class that controls the plug-in\u2019s life cycle option button. For the purposes of this example, a single class will be used. An Activator class will not be created; instead, OSGi Declarative Services will be used to start and stop the bundle.
Finally, click Finish.
You should see the new project in the Package Explorer (or Project Explorer) in Eclipse. Also, you will see the MANIFEST.MF was automatically opened in the Manifest Editor. An OSGi bundle is a regular Java .jar file that contains Java code and resources and a custom Manifest and an Activator. The manifest will be modified in the next section.
"},{"location":"java-application-development/configurable-application/#add-dependencies-to-manifest","title":"Add Dependencies to Manifest","text":"First, you will use the Manifest Editor in Eclipse to add some dependencies. Click the Dependencies tab at the bottom of the editor screen and then click the Automated Management of Dependencies heading to expand it.
Under Automated Management of Dependencies, click Add. In the Select a Plug-in field, enter org.eclipse.osgi.services. Select the plug-in name and click OK.
Note that this operation is very much like adding standalone jars to the buildpath by including the \u2018-cp\u2019 argument to javac. However, in this case you are telling Eclipse where to find these dependencies the \u201cOSGi way\u201d, so it is aware of them at compile time.
Click Add again and use the same procedure to add the following dependencies:
You should now see the list of dependencies. Save changes to the Manifest.
"},{"location":"java-application-development/configurable-application/#create-java-class","title":"Create Java Class","text":"Now you are ready to start writing a simple Java class. Right-click the org.eclipse.kura.example.configurable project. Select New | Class. Set the Package field to org.eclipse.kura.example.configurable, set the Name field to ConfigurableExample, and then click Finish.
Write the following code for the new class. You can copy and paste the code provided below into your newly created Java class file.
package org.eclipse.kura.example.configurable;\n\npublic class ConfigurableExample implements ConfigurableComponent {\n private static final Logger s_logger = LoggerFactory.getLogger(ConfigurableExample.class);\n private static final String APP_ID = \"org.eclipse.kura.example.configurable.ConfigurableExample\";\n private Map<String, Object> properties;\n\n protected void activate(ComponentContext componentContext) {\n s_logger.info(\"Bundle \" + APP_ID + \" has started!\");\n }\n\n protected void activate(ComponentContext componentContext, Map<String, Object> properties) {\n s_logger.info(\"Bundle \" + APP_ID + \" has started with config!\");\n updated(properties);\n }\n\n protected void deactivate(ComponentContext componentContext) {\n s_logger.info(\"Bundle \" + APP_ID + \" has stopped!\");\n }\n\n public void updated(Map<String, Object> properties) {\n this.properties = properties;\n if(properties != null && !properties.isEmpty()) {\n Iterator<Entry<String, Object>> it = properties.entrySet().iterator();\n while (it.hasNext()) {\n Entry<String, Object> entry = it.next();\n s_logger.info(\"New property - \" + entry.getKey() + \" = \" +\n entry.getValue() + \" of type \" + entry.getValue().getClass().toString());\n }\n }\n }\n}\n
The activate() method is the entry point when the bundle is started. Note this class has two forms of the activate() method. The second method (with the \u201cMap properties\u201d parameter) enables a default configuration to be specified at bundle start time. The deactivate() method is the entry point when the bundle is stopped. You have also specified an updated() method. These methods define how the bundle receives a new configuration from the Kura configuration manager. Kura handles robust configuration management routines automatically once you implement the ConfigurableComponent interface and the updated() method."},{"location":"java-application-development/configurable-application/#resolve-dependencies","title":"Resolve Dependencies","text":"
At this point, there will be errors in your code because of unresolved imports.
Select the menu Source | Organize Imports to resolve these errors. Because you added dependencies to your dependency list in the Manifest, you will be prompted to choose one of the following two potential sources for importing a few classes.
For the \u201cEntry\u201d class, select java.util.Map.Entry as shown below and click Next.
For the \u201cLogger\u201d class, select org.slf4j.Logger as shown below and click Finish.
Resolving the imports should clear the errors in the class as shown in the screen capture that follows. Save the changes to the ConfigurableExample class.
The complete set of code (with import statements) is shown below.
package org.eclipse.kura.example.configurable;\n\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\n\npublic class ConfigurableExample implements ConfigurableComponent {\n\n private static final Logger s_logger = LoggerFactory.getLogger(ConfigurableExample.class);\n private static final String APP_ID* = \"org.eclipse.kura.configurable.ConfigurableExample\";\n private Map<String, Object> properties;\n\n protected void activate(ComponentContext componentContext) {\n s_logger.info(\"Bundle \" + APP_ID + \" has started!\");\n }\n\n protected void activate(ComponentContext componentContext, Map<String, Object> properties) {\n s_logger.info(\"Bundle \" + APP_ID + \" has started with config!\");\n updated(properties);\n }\n\n protected void deactivate(ComponentContext componentContext) {\n s_logger.info(\"Bundle \" + APP_ID + \" has stopped!\");\n }\n\n public void updated(Map<String, Object> properties) {\n this.properties = properties;\n if(properties != null && !properties.isEmpty()) {\n Iterator<Entry<String, Object>> it = properties.entrySet().iterator();\n while(it.hasNext()) {\n Entry<String, Object> entry = it.next();\n s_logger.info(\"New property - \" + entry.getKey() + \" = \" +\n entry.getValue() + \" of type \" + entry.getValue().getClass().toString());\n }\n }\n }\n}\n
Switch back to the Manifest Editor. Under Automated Management of Dependencies, ensure the Import-Package option button is selected. Click the add dependencies link to automatically add packages to the dependencies list (under Imported Packages) based on the \u201cimport\u201d statements in your example code. Save changes to the Manifest again.
"},{"location":"java-application-development/configurable-application/#create-component-class","title":"Create Component Class","text":"Right-click the example project and select New | Folder. Create a new folder named \u201cOSGI-INF\u201d.
Now, right-click the example project\u2019s \u201cOSGI-INF\u201d folder and select New | Other. From the wizard, select Plug-in Development | Component Definition and click Next.
Next to the Class field, click Browse and type the name of your newly created class in the Select entries field. In this case, type the word \u201cConfigurable\u201d, and you will see matching items. Select the ConfigurableExample class and click OK.
In the Enter or select the parent folder field, make sure \u201c/OSGI-INF\u201d is at the end of the existing entry (e.g., org.eclipse.kura.example.configurable/OSGI-INF). Set the Name field equal to the Class field as shown below:
Click Finish.
After the Component class has been created, it will open in the Workspace. On the Services tab, click the Add button under Provided Services. Enter \u201cconfigurable\u201d and select the interface \u201corg.eclipse.kura.example.configurable\u201d. This is required for components that are configurable through the Kura ConfigurationService, so that they expose a Service.
In the Overview tab, the Name and Class fields should already point to your Java class. Make the following settings:
Set the Activate field to activate and set the Deactivate field to deactivate. This tells the component where these OSGi activation methods are located.
Set the Configuration Policy to require.
Set the Modified field to updated. This tells the component which method to call when the configuration is updated.
Uncheck the box This component is enabled when started, then check both boxes This component is enabled when started and This component is immediately activated.
Click the Add Property button. Enter a property with the name \u201cservice.pid\u201d and value \u201corg.eclipse.kura.example.configurable.ConfigurableExample\u201d as shown in the screen capture below.
Verify that the completed Overview tab looks like the screen shot shown below and save the Component class definition file:
Check the Source tab of the component.xml file and carefully verify that each of the property values and tags match what is shown below:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\"\n activate=\"activate\"\n configuration-policy=\"require\"\n deactivate=\"deactivate\"\n enabled=\"true\"\n immediate=\"true\"\n modified=\"updated\"\n name=\"org.eclipse.kura.example.configurable.ConfigurableExample\">\n\n <implementation class=\"org.eclipse.kura.example.configurable.ConfigurableExample\"/>\n <service>\n <provide interface=\"org.eclipse.kura.example.configurable.ConfigurableExample\"/>\n </service>\n <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.example.configurable.ConfigurableExample\"/>\n</scr:component>\n
If Kura 3.0 or newer versions are used and the \"org.eclipse.kura.core.configuration.legacyServiceTracking\" system property is set to false or not set, proceed as follows.
"},{"location":"java-application-development/configurable-application/#create-the-default-configuration","title":"Create the Default Configuration","text":"With the component definition file created, you also need to specify the configurable parameters of this bundle. This is done using the \u201cmetatype\u201d definition. Right-click the OSGI-INF directory for the example project in the Package Explorer window and select New | Folder. Name the folder \u201cmetatype\u201d. Next, right-click the metatype folder and select New | File.
Name the file \u201corg.eclipse.kura.example.configurable.ConfigurableExample.xml\u201d as shown in the following screen capture:
At this point, you have to write the \u2018metatype\u2019 file that defines the parameters, default values, types, etc. Click on the Source button and paste the following XML text into ConfigurableExample.xml for this example. Save changes to ConfigurableExample.xml.
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n <OCD id=\"org.eclipse.kura.example.configurable.ConfigurableExample\"\n name=\"ConfigurableExample\"\n description=\"This is a sample metatype file for a simple configurable component\">\n\n <AD id=\"param1.string\"\n name=\"param1.string\"\n type=\"String\"\n cardinality=\"0\"\n required=\"true\"\n default=\"Some Text\"\n description=\"String configuration parameter\"/>\n\n <AD id=\"param2.float\"\n name=\"param2.float\"\n type=\"Float\"\n cardinality=\"0\"\n required=\"false\"\n default=\"20.5\"\n min=\"5.0\"\n max=\"40.0\"\n description=\"Float configuration parameter\"/>\n\n <AD id=\"param3.integer\"\n name=\"param3.integer\"\n type=\"Integer\"\n cardinality=\"0\"\n required=\"true\"\n default=\"2\"\n min=\"1\"\n description=\"Integer configuration parameter\"/>\n </OCD>\n\n <Designate pid=\"org.eclipse.kura.example.configurable.ConfigurableExample\">\n <Object ocdref=\"org.eclipse.kura.example.configurable.ConfigurableExample\"/>\n </Designate>\n</MetaData>\n
In the MANIFEST.MF of this bundle, you must also make sure the XML file gets packaged into the bundle when you export the plug-in. Click the Build tab, and in the Binary Build section of the Manifest editor verify that all the checkboxes for items under META-INF and OSGI-INF are checked. Save the Manifest after making this change.
"},{"location":"java-application-development/configurable-application/#run-the-bundle","title":"Run the Bundle","text":"At this point, you can run the bundle using the emulator in Eclipse (Linux or OS X only). To do so, expand the org.eclipse.kura.emulator project in the package explorer and browse to src/main/resources. As appropriate for you platform type, right-click Kura_Emulator_[OS].launch (where \u201c[OS]\u201d specifies your operating system) and select Run as | KURA_EMULATOR_[OS].launch. Doing so will start the Kura emulator and your new bundle in the console window of Eclipse.
"},{"location":"java-application-development/configurable-application/#view-the-bundle-configuration-in-the-local-web-ui","title":"View the Bundle Configuration in the Local Web UI","text":"With the bundle running, open a browser window on the same computer as the Eclipse development environment and browse to the Kura web UI at http://127.0.0.1:8080. Once connected to the Kura web UI, a log in window appears prompting you to enter the Name and Password as shown below:
Enter the appropriate name and password (default is admin/admin) and click Log in. The Kura Admin web UI appears with the ConfigurableExample in the Services area on the left side of the browser window as shown below:
From the Kura Admin web UI, you can change the parameters that are used by the Kura configuration manager and in turn call the updated() method of the newly created bundle. To do so, click ConfigurableExample and the configurable component parameters will be displayed as shown below:
Make any necessary changes and click the Apply button near the top left of the configuration pane for the modifications to take affect. Every time a change is made to the configuration, a new snapshot is generated along with an ID.
"},{"location":"java-application-development/connected-application/","title":"Connected Application","text":""},{"location":"java-application-development/connected-application/#overview","title":"Overview","text":"This section describes the prepackaged heater demo bundle that comes with the Kura development environment and demonstrates how to perform the following functions:
Run the Kura Emulator
Connect to the Cloud
Gain an understanding of ConfigurableComponents in Kura
Modify configurations of custom bundles
Setting up Kura Development Environment
Using the Kura web UI
The org.eclipse.kura.demo.heater bundle is a simple OSGi bundle that represents a thermostat and heater combination. The application utilizes the Kura ConfigurableComponent interface to be able to receive configuration updates through the local Kura web UI. In addition, this bundle utilizes OSGi declarative services and the Kura CloudClientListener. This tutorial demonstrates how to modify configurations of custom bundles and shows how those configuration changes can dynamically impact the behavior of the bundle through the Kura web UI.
"},{"location":"java-application-development/connected-application/#code-walkthrough","title":"Code Walkthrough","text":"The following sections will highlight three important API layers when creating an application that will publish to the cloud. These layers are:
The CloudService can manage multiple applications over a shared MQTT connection by treating each application as a client. The example code uses the \"setCloudService\" and \"unsetCloudService\" methods for referencing and releasing the CloudService. In the bundles activate method, the service reference in conjunction with a unique application ID can then be used to obtain a CloudClient. The relevant code is shown below (ommitted sections are denoted by ==OMMITTED==):
==OMMITTED==\n// Cloud Application identifier\nprivate static final String APP_ID = \"heater\";\n\n==OMMITTED==\n\npublic void setCloudService(CloudService cloudService) {\n m_cloudService = cloudService;\n}\n\npublic void unsetCloudService(CloudService cloudService) {\n m_cloudService = null;\n}\n\n==OMMITTED==\n\n// Acquire a Cloud Application Client for this Application\ns_logger.info(\"Getting CloudClient for {}...\", APP_ID);\nm_cloudClient = m_cloudService.newCloudClient(APP_ID);\n
"},{"location":"java-application-development/connected-application/#publishingsubscribing","title":"Publishing/Subscribing","text":"The private \"doPublish\" method is used to publish messages at a fixed rate. The method demonstrates how to use the CloudClient and KuraPayload to publish MQTT messages.
==OMMITTED==\n\n// Allocate a new payload\nKuraPayload payload = new KuraPayload();\n\n// Timestamp the message\npayload.setTimestamp(new Date());\n\n// Add the temperature as a metric to the payload\npayload.addMetric(\"temperatureInternal\", m_temperature);\npayload.addMetric(\"temperatureExternal\", 5.0F);\npayload.addMetric(\"temperatureExhaust\", 30.0F);\n\nint code = m_random.nextInt();\nif ((m_random.nextInt() % 5) == 0) {\n payload.addMetric(\"errorCode\", code);\n}\nelse {\n payload.addMetric(\"errorCode\", 0);\n}\n\n// Publish the message\ntry {\n m_cloudClient.publish(topic, payload, qos, retain);\n s_logger.info(\"Published to {} message: {}\", topic, payload);\n}\ncatch (Exception e) {\n s_logger.error(\"Cannot publish topic: \"+topic, e);\n}\n
Similarly, the CloudClient can be used to subscribe to MQTT topics. Although not shown in the example code, the following snippet could be added to subscribe to all published messages:
m_cloudClient.subscribe(topic, qos);\n
"},{"location":"java-application-development/connected-application/#callback-methods","title":"Callback Methods","text":"The example class implements CloudClientListener, which provides methods for several common callback methods. The below snippet shows the relevant code for creating the listeners for the demo application.
==OMMITTED==\n\npublic class Heater implements ConfigurableComponent, CloudClientListener\n\n==OMMITTED==\n\nm_cloudClient.addCloudClientListener(this);\n
The available methods for implementation are:
For more information on the various Kura APIs, please review the Kura APIs
"},{"location":"java-application-development/connected-application/#run-the-bundle","title":"Run the Bundle","text":"By default, the heater demo bundle does not run automatically. To run the bundle and Kura in the Emulator, locate the org.eclipse.kura.emulator project. Expand it to show the src/main/resources folder.
Right-click the correct Kura_Emulator_[OS].launch file, depending on which operating system you are running. In the context menu, select the Run As option, and click on Run Configurations.
Under OSGi Framework (Run Configurations window shown below), click on the Kura_Emulator_[OS] entry. In the Bundles tab under Workspace, enable the org.eclipse.kura.demo.heater checkbox to enable it as shown below:
Click the Apply and Run buttons to start the Kura Emulator. Once this setting has been made, you only need to right-click on the launch file and select Run As and the Kura_Emulator_[OS] option to run with the same settings.
This will start Kura running locally and will display a Console window in Eclipse. The Console window will show the OSGi diagnostics as various bundles start and execute.
"},{"location":"java-application-development/connected-application/#configure-the-mqtt-client","title":"Configure the MQTT Client","text":"With the heater demo bundle running, open a browser window on the same computer as the Eclipse development environment and browse to the Kura web UI at http://127.0.0.1:8080. Once connected to the Kura web UI, a log in window appears prompting you to enter the Name and Password as shown below:
Enter the appropriate name and password (default is admin/admin) and click Log in. The Kura Admin web UI appears as shown below:
From the Kura web UI, click on MqttDataTransport in the Services pane on the lower left of the browser window. You will see a menu similar to the one shown in the following screen capture:
Fill in the following fields then click the Apply button:
Field Value broker-url: The url for the MQTT broker (this example shows the MQTT broker-url mqtt://iot.eclipse.org:1883/ hosted by the Eclipse Foundation) topic.context.account-name: Your [account_name] username: Typically [account_name]_broker password: The password for your user client-id The client identifier to be used when connecting to the MQTT broker (optional)Now that the account credentials are set in the MqttDataTransport service, the DataService needs to be configured to connect by default. To do so, click DataService in the Services area on the left of the browser window. For the \u2018connect.auto-on-startup\u2019 parameter, select true as shown below:
"},{"location":"java-application-development/connected-application/#modify-bundle-configuration-in-local-web-ui","title":"Modify Bundle Configuration in Local Web UI","text":"Bundles changes may be made directly in the emulator web UI. Since you are running an emulated device in Eclipse, you can do this by browsing to http://127.0.0.1:8080 (same URL where the MQTT client was configured in the previous section of this tutorial). If the bundle was running on a real device and you had network access to it, you would browse to http://[ip_address_of_device].
From the Kura web UI, select the Heater bundle from the configurable services on the left and modify the parameters as needed (shown in the screen capture below). By default, the heater demo is configured according to the following characteristics and assumptions about its operational environment:
Start operation is at 6:00am (06:00).
End operation is at 10:00pm (22:00).
It is colder outside than inside the heated chamber (hard-coded to 5 degrees in the application).
Output of the heater is constant at 30 degrees (hard-coded).
When in operational mode, the temperature will drop inside if the heater is off.
The heater turns off when it is about to exceed the setPoint defined in the configuration.
After the temperature drops to four times the increment point (a made-up value to show dropping temperature, hard-coded in the application), the heater turns back on, and the temperature starts increment at the rate of the \u2018temperature.increment\u2019 rate.
Click Apply for changes to take affect. The updated() method is called after settings are applied for the new configuration.
After completing this tutorial, it is highly recommended that you review the heater demo source code in Eclipse to see how it is put together. Kura automatically generates the user configuration interface through implementation of the ConfigurableComponent interface and some small additions to the component.xml file (called heater.xml). This powerful feature provides both a local and remote configuration user interface with no additional development requirements.
"},{"location":"java-application-development/contributing/","title":"Contributing","text":"Contributing to Eclipse Kura project is very easy.
The steps required to submit code to the project can be found on Github Contributing Page.
If you face any issues, or just want to get involved with the kura community feel free to join us on:
If you want to get involved in the development process you can join us at the Kura Dev Meeting. The meeting is held every 2 weeks on Wednesday, at 5 PM CEST on Microsoft Teams.
You can join by using this link.
The scheduled dates for the meeting can be found here. Unzip the calendar file and double-click on it to add the scheduled dates to your calendar.
"},{"location":"java-application-development/deploy-and-debug-applications/","title":"Deploy and Debug Applications","text":""},{"location":"java-application-development/deploy-and-debug-applications/#overview","title":"Overview","text":"This section provides a simple example of how to test and deploy OSGi bundles and deployment packages in a Kura environment. These instructions use the \u201cHello World\u201d OSGi project created in the previous section. In this example, you will learn how to perform the following functions:
Use local OSGi emulation mode in Eclipse
Deploy a bundle to a remote target running the OSGi Framework
Install a Deployment Package to a remote target running the OSGi Framework
Manage OSGi bundles on a target device
Set bundle Logger levels in Kura
Setting up Kura Development Environment
Hello World Using the Kura Logger
Once you have created an OSGi plug-in, you can test it in Local Emulation Mode and/or deploy it to a Remote Target Device.
"},{"location":"java-application-development/deploy-and-debug-applications/#local-emulation-mode","title":"Local Emulation Mode","text":"The Kura user workspace can be used in Eclipse in local emulation mode (Linux/OS X only; this feature is not currently supported under Windows). To deploy the code to a running system, see the section Remote Target Device.
"},{"location":"java-application-development/deploy-and-debug-applications/#run-kura-in-emulator-mode","title":"Run Kura in Emulator Mode","text":"In the Eclipse workspace, locate the org.eclipse.kura.emulator project. Expand it to show the src/main/resources folder.
Right-click the Kura_Emulator.launch file. In the context menu, select the Run as option, and select the Kura_Emulator*. This will start Kura running locally and will display a Console window in the bottom pane in Eclipse. The Console window will show the OSGi diagnostics as various bundles start and execute.
Because the org.eclipse.kura.example.hello_osgi bundle is in the workspace with a valid activate() method, it is automatically started with the Kura OSGi framework. Note the INFO message highlighted below that shows the bundle\u2019s activate() method was run.
"},{"location":"java-application-development/deploy-and-debug-applications/#list-osgi-bundles-in-local-mode","title":"List OSGi Bundles in Local Mode","text":"With the OSGi framework running in the Eclipse console (refer to the previous section), click in the Console window. Press Enter/Return and then type the \u2018ss\u2019 command to show a list of installed bundles. Note the bundle ID number for the org.eclipse.kura.example.hello_osgi bundle.
"},{"location":"java-application-development/deploy-and-debug-applications/#startstop-bundle-in-local-mode","title":"Start/Stop Bundle in Local Mode","text":"In the OSGi Console window in Eclipse, run the
start ##
or stop ##
commands to start or stop a bundle, where the \u201c##\u201d is either the bundle ID number or the bundle name (such as \u201cstart org.eclipse.kura.example.hello_osgi\u201d). Note that the INFO messages for both the activate() and deactivate() messages appear in the Console window when the bundle is started or stopped.
"},{"location":"java-application-development/deploy-and-debug-applications/#installuninstall-bundle-in-local-mode","title":"Install/Uninstall Bundle in Local Mode","text":"In the OSGi Console window in Eclipse, bundles can be installed or uninstalled. To uninstall the example bundle, issue the command \u2018uninstall ##\u2019, where \u201c##\u201d is either the bundle ID number or the bundle name, such as:
uninstall 47
or uninstall org.eclipse.kura.example.hello_osgi
A message will appear indicating that the bundle has been stopped.
Once the bundle has been uninstalled from the local OSGi console, it cannot be started or installed by number or name. Instead, it must be installed by using the plug-in JAR file created earlier. Issue the \u2018install\u2019 command to install a bundle into the Emulation environment:
install file:/[*path_to_bundle*]/[*bundle_name*].jar
where \u201c[path_to_bundle]/[bundle_name].jar\u201d should be replaced with the name of the bundle exported earlier (the section Hello World Using the Kura Logger), as shown in the example below:
install file:/Users/Nina/Documents/myPlugins/plugins/plugins/plugins/plugins/plugins/org.eclipse.kura.example.hello_osgi_ 1.0.0.201409101740.jar
Then the bundle can be started or stopped, as described in the previous section, Start/Stop Bundle in Local Mode. Optionally, you can add the flag \u2018-start\u2019 to the \u2018install\u2019 command to automatically start the bundle after installation.
"},{"location":"java-application-development/deploy-and-debug-applications/#remote-target-device","title":"Remote Target Device","text":"One or more OSGi bundles can be deployed to a remote device running Kura, either by installing separate bundle files or deployment packages using Eclipse.
Warning
These steps require Kura to be running on the target device.
This method of deployment is temporary on the remote target device and is not persistent after a restart. To make the deployment permanent, see Making Deployment Permanent.
"},{"location":"java-application-development/deploy-and-debug-applications/#connect-to-remote-osgi-framework","title":"Connect to Remote OSGi Framework","text":"To deploy a bundle to the remote target device, you will need to connect Eclipse to the OSGi framework running on the device. This is done using mToolkit. See Kura Setup for instructions on installing mToolkit into the Eclipse development environment.
Select the Eclipse menu Window | Show View | Other.
Select mToolkit -> Frameworks entry to open the mToolkit Frameworks view.
Enter a name for the framework definition and the IP address of the target device.
Close the dialog by clicking the OK button.
Warning
The remote target device must have port 1450 open in its firewall, in order to allow mToolkit o make a connection to its OSGi framework. If this port is not opened, refer to the section Open Port for OSGi Remote Connection.
Right-click the framework icon name and select Connect Framework. The list of installed bundles and deployment packages should be retrieved shortly. (Use the Disconnect Framework option to disconnect from the remote target framework when finished.)
"},{"location":"java-application-development/deploy-and-debug-applications/#open-port-for-osgi-remote-connection","title":"Open Port for OSGi Remote Connection","text":"In order to allow mToolkit to make a remote connection to the OSGi framework on the target device, the device must allow the incoming port in its firewall. To set this option, open a Web browser and log into Kura using its current IP address, such as:
http://10.11.5.4
Click the Firewall icon and then click the Open Ports tab. If port 1450 is not shown in the list of allowed ports, click the New button under Open Ports. Enter the port 1450 and select protocol TCP. Then click Submit.
Now, click Apply to apply changes to the remote device.
"},{"location":"java-application-development/deploy-and-debug-applications/#install-single-bundle-to-target-device","title":"Install Single Bundle to Target Device","text":"With the Eclipse environment connected to the remote OSGi target framework, a single bundle can be installed on the remote device.
In the mToolkit Frameworks view, right-click the Framework name and select Install Bundle. (This requires that you have exported the bundle as a deployable plug-in JAR file. See the section Hello World Using the Kura Logger.)
Use the Browse button to select the JAR file and click OK to install it to the target device.
The newly installed bundle should be shown in the Frameworks view under Bundles.
To control operation of the bundle through the OSGi Frameworks view, right-click the bundle name. The following actions can be performed:
Start \u2013 start the bundle
Stop \u2013 stop the bundle
Update \u2013 reinstall the bundle
Install Bundle \u2013 install a different bundle
Uninstall Bundle \u2013 remove this bundle from the target device
Show Bundle IDs / Show Bundle Versions \u2013 show additional information about bundles
You can also verify operation of the bundle on the target device itself. See the section Manage Bundles on Target Device.
"},{"location":"java-application-development/deploy-and-debug-applications/#install-deployment-package-to-target-device","title":"Install Deployment Package to Target Device","text":"With the Eclipse environment connected to the remote OSGi target framework, a deployment package can be installed on the remote device.
NOTE: If you have just installed the individual bundle in the previous section, you should uninstall it before proceeding. Doing so will avoid any confusion in having the same bundle installed twice.
In the mToolkit Frameworks view, right-click the Framework name and select Install Deployment Package. (This step requires that you have exported the bundle as a deployable plug-in JAR file. See the section Hello World Using the Kura Logger for instructions on exporting the OSGi bundle.)
Open the resources/dp folder in the Workspace filesystem directory, select the .dp file (not the \u201c.dpp\u201d file), and click OK.
The deployment package will be installed on the target device and shown in the Frameworks view under Deployment Packages. (The deployment package can also be uninstalled from the Framework view.)
The bundle included in the deployment package can also be viewed under Bundles and can be controlled remotely (start/stop) as with other bundles. The operation of the bundle can also be verified on the target device itself. See the section Manage Bundles on Target Device.
"},{"location":"java-application-development/deploy-and-debug-applications/#connect-to-osgi-on-target-device","title":"Connect to OSGi on Target Device","text":"You can manage the OSGi framework on a target device by logging into a console on the device using a connected keyboard and VGA monitor or over a network connection using SSH (PuTTY in Windows or \u2018ssh\u2019 from Linux or Mac).
At the command prompt, display the Kura log file with:
tail -f /var/log/kura.log
Connect to the OSGi framework by typing the following commands:
telnet localhost 5002
There are many commands available in the OSGi console for managing bundles. Following are just a few useful commands:
Command Description ss Lists names and ID of bundles help Displays the help menu of OSGi commands lb Lists all installed bundles and IDs h [bundle IDs] Displays bundle headers (i.e., Bundle Manifest Version, Name, Required Execution Environment, Symbolic Name, Version, Import Package, Manifest Version, and Service Component) exit Exits the OSGi console and stops Kura disconnect Exits the OSGi console, but leaves Kura running"},{"location":"java-application-development/deploy-and-debug-applications/#manage-bundles-on-target-device","title":"Manage Bundles on Target Device","text":"From the OSGi command line, you can display a list of bundles with the \u2018ss\u2019 command as shown in the example below:
ss
In this example, the org.eclipse.kura.example.hello_osgi bundle ID is 64.
You can run the \u2018start ##\u2019 or \u2018stop ##\u2019 commands to start or stop a bundle, where the \u201c##\u201d is either the bundle ID number or the bundle name (such as \u201cstart org.eclipse.kura.example.hello_osgi\u201d). To verify that the bundled is stopped, you can issue the \u2018ss\u2019 command. If the bundled is stopped, the activity will show RESOLVED (as shown below). If the bundle is started, the activity will show ACTIVE (as shown above).
"},{"location":"java-application-development/deploy-and-debug-applications/#set-kura-logger-levels","title":"Set Kura Logger Levels","text":"Kura logger levels are defined in a configuration file. The messages that appear require a log statement in the application and that the log level of the statement matches the log level of the application (such as logger.info or logger.debug).
To set or change logger levels, the Kura logger configuration file may be modified using the vi editor. From the Linux command prompt, enter the following command:
vi /opt/eclipse/kura/kura/log4j.properties
At the bottom of the \u201clog4j.properties\u201d file, there will be one or more \u201clog4j\u201d logger property entries, which determine the logger level used by the bundles at startup.
In the example screen capture shown below, the \u201clog4j.logger.org.eclipse.kura\u201d property has been set to \u201cINFO\u201d, which applies to all bundles that start with \u201corg.eclipse.kura.\u201d Additional, more specific, properties may be defined as required for your particular logging needs. The property entries will take on the defined logger level at startup. The logger levels are hierarchical, so that those in a deeper level of the hierarchy will apply; otherwise, the more general logger level will override them.
Once you have made the necessary changes, save and close the file using the \u2018:wq\u2019 command. Restart Kura, and check the log levels in the OSGi console again to make sure that the desired levels have taken effect.
"},{"location":"java-application-development/deploy-and-debug-applications/#making-deployment-permanent","title":"Making Deployment Permanent","text":"The mToolkit deployment of a package is a temporary installation and does not make the package permanent. Once a set of bundles has been tested on the remote target device and is ready for permanent deployment, the software can be installed on a device with deployment packages from the command line of a target device using the instructions below:
/opt/eclipse/kura/kura/packages
vi /opt/eclipse/kura/kura/dpa.properties
package_name=file\\:/opt/eclipse/kura/kura/packages/package_filename.dp
where, \u201cpackage_name\u201d and \u201cpackage_filename\u201d should be replaced with the actual name of the deployment package.
Save and close the file using the \u2018:wq\u2019 command.
Then restart Kura, and the new package should be installed in addition to the default Kura package.
In conclusion, this section described how to test a bundle in an Emulation environment within the Eclipse IDE and how to install bundles and Deployment Packages to a remote target system running Kura.
"},{"location":"java-application-development/development-environment-setup/","title":"Development Environment Setup","text":"In this document we'll cover the required steps to setup the Development Environment for contributing to the Eclipse Kura project. If, instead, you want to develop applications or bundles running on Eclipse Kura refer to the Eclipse Kura Workspace setup guide.
The Eclipse Kura development environment may be installed on Windows, Linux, or Mac OS. The setup instructions will be the same across each OS though each system may have unique characteristics.
Info
The local emulation of Eclipse Kura code is only supported in Linux and Mac, not in Windows.
This document will cover the use of Eclipse Oomph installer which is the easiest way to install and configure the Eclipse IDE to start contributing to Eclipse Kura.
The setup requires three basic steps:
Before building Eclipse Kura, you need to have the following programs installed in your system:
Recommended additional software:
To install Java 8, download the JDK tar archive from the Adoptium Project Repository.
Once downloaded, copy the tar archive in /Library/Java/JavaVirtualMachines/
and cd into it. Unpack the archive with the following command:
sudo tar -xzf <archive-name>.tar.gz\n
The tar archive can be deleted afterwards. Depending on which terminal you are using, edit the profiles (.zshrc, .profile, .bash_profile) to contain:
# Adoptium JDK 8\nexport JAVA_8_HOME=/Library/Java/JavaVirtualMachines/<archive-name>/Contents/Home\nalias java8='export JAVA_HOME=$JAVA_8_HOME'\njava8 \n
Reload the terminal and run java -version
to make sure it is installed correctly. Using Brew you can easily install Maven from the command line:
brew install maven@3.5\n
Run mvn -version
to ensure that Maven has been added to the PATH. If Maven cannot be found, try running brew link maven@3.5 --force
or manually add it to your path with: export PATH=\"/usr/local/opt/maven@3.5/bin:$PATH\"\n
"},{"location":"java-application-development/development-environment-setup/#installing-prerequisites-in-linux","title":"Installing Prerequisites in Linux","text":"For Java
sudo apt install openjdk-8-jdk\n
For Maven
You can follow the tutorial from the official Maven site. Remember that you need to install 3.5.x version or greater.
"},{"location":"java-application-development/development-environment-setup/#eclipse-oomph-setup","title":"Eclipse Oomph setup","text":"Download the latest Eclipse Installer appropriate for your platform from the Eclipse Downloads page and start it.
Switch to \"Advanced Mode\" (top right hamburger menu) and select \"Eclipse IDE for Eclipse Committers\" and configure the \"Product Version\" to be the version 2023-03 or newer.
Select the Eclipse Kura installer from the list. If this is not available, add a new installer from https://raw.githubusercontent.com/eclipse/kura/develop/kura/setups/kura.setup, then check and press the \"Next\" button.
Variables setup
JRE 1.8 location
value to the installed local jdk-8 VMIf you plan to contribute to Eclipse Kura you might want to create a fork, see our contributing guide for further informations. For the purpose of this tutorial we'll work with a fictional fork for the username user
. To clone the repo use the link appropriate for your fork, in our case it will be: https://github.com/user/kura.git
Keep in mind that the \"Root install folder\" is where the Eclipse executable will be installed and the Eclipse Kura sources will be downloaded (in the git
subfolder).
Press Next, leave all Bootstrap Tasks selected and press the Finish button
Accept all the licenses and wait for the installation to finish.
At first startup Eclipse IDE will checkout the code, perform a full build and configure a few Working Sets
When the tasks are completed, go to into the Package Explorer and Target Platform > Target-Definition > Kura Target Platform Equinox 3.16.0, and press \"Set as Target Platform\" located at the top right of the window:
"},{"location":"java-application-development/development-environment-setup/#eclipse-kura-maven-build","title":"Eclipse Kura maven build","text":"Navigate to the git
folder created within the Eclipse workspace (~/iot-kura-workspace
in the example above) and build the target platform:
mvn -f target-platform/pom.xml clean install\n
Then build the core components:
mvn -f kura/pom.xml clean install\n
Build the examples (optional):
mvn -f kura/examples/pom.xml clean install\n
Build the target profiles:
mvn -f kura/distrib/pom.xml clean install -DbuildAll\n
Note
You can skip tests by adding -Dmaven.test.skip=true
in the commands above and you can compile a specific target by specifying the profile (e.g. -Praspberry-pi-armhf
).
Alternatively you can use the build scripts available in the root directory.
./build-all.sh\n
or
./build-menu.sh\n
and select the profiles you want to build.
"},{"location":"java-application-development/hello-world-application/","title":"Hello World Application","text":""},{"location":"java-application-development/hello-world-application/#overview","title":"Overview","text":"This section provides a simple example of how to create a Kura \u201cHello World\u201d OSGi project using Eclipse. With this example, you will learn how to perform the following functions:
Create a plugin project
Consume the Kura Logger service
Write an OSGi Activator
Export a single OSGi bundle (plug-in)
Create a Deployment Package
Setting up the Kura Development Environment
"},{"location":"java-application-development/hello-world-application/#hello-world-using-the-kura-logger","title":"Hello World Using the Kura Logger","text":""},{"location":"java-application-development/hello-world-application/#create-hello-world-plug-in","title":"Create Hello World Plug-in","text":"In Eclipse, create a new Plug-in project by selecting File | New | Project. Select Plug-in Development | Plug-in Project and click Next.
Your screen should display the New Plug-in Project dialog box as shown in the following screen capture. Enter your project a name, such as \u201corg.eclipse.kura.example.hello_osgi\u201d, in the appropriate field. Under Target Platform, ensure that the an OSGi framework option button is selected and set the variable to standard as shown below. You can also (optionally) add projects to a working set. To continue, click Next.
In the next New Plug-in Project menu (shown below), change the Name field to a descriptive name, such as \u201cHello World Example with Logger\u201d.
Also, verify that the Execution Environment list is set to match the Java JVM version running on the target device (JavaSE-1.8 or JavaSE-11). To determine the JVM version running on the target device, log in to its administrative console and enter the command
java \u2013version
Finally, uncheck the Generate an activator, a Java class that controls the plug-in\u2019s life cycle option button. For the purposes of this example, a single class will be used. An Activator class will not be created; instead, OSGi Declarative Services will be used to start and stop the bundle.
Click Finish.
If the Open Associated Perspective pop-up window (shown below) appears for adding Plug-ins and Error Log views, select Yes or No depending on your development requirements.
You should see the new project in the My Projects working set in the Package Explorer (or Project Explorer). Also, you will see the MANIFEST.MF was automatically opened in the Manifest Editor. An OSGi bundle is a regular Java .jar file that contains Java code and resources and a custom Manifest and an Activator.
"},{"location":"java-application-development/hello-world-application/#add-dependencies-to-manifest","title":"Add Dependencies to Manifest","text":"First, you will use the Manifest Editor in Eclipse to add some dependencies. Click the Dependencies tab at the bottom of the editor screen and then click the Automated Management of Dependencies heading to expand it.
Under Automated Management of Dependencies, click Add. In the Select a Plug-in field, enter org.eclipse.osgi.services. Select the plug-in name and click OK.
Note that this operation is very much like adding standalone jars to the buildpath by including the \u2018-cp\u2019 argument to javac. However, in this case you are telling Eclipse where to find these dependencies the \u201cOSGi way\u201d, so it is aware of them at compile time. Click Add again and use the same procedure to add the following dependency:
You should now see the list of dependencies. Save changes to the Manifest.
"},{"location":"java-application-development/hello-world-application/#create-java-class","title":"Create Java Class","text":"Now you are ready to start writing a simple Java class. Right-click the org.eclipse.kura.example.hello_osgi project. Select New | Class. The New Java Class window appears as shown below. Set the Source folder to org.eclipse.kura.example.hello_osgi/src. Set the Package field to org.eclipse.kura.example.hello_osgi, set the Name field to HelloOsgi, and then click Finish.
Write the following code for the new class. You can copy and paste the code provided below into your newly created Java class file.
package org.eclipse.kura.example.hello_osgi;\n\npublic class HelloOsgi {\n\n private static final Logger s_logger = LoggerFactory.getLogger(HelloOsgi.class);\n\n private static final String APP_ID = \"org.eclipse.kura.example.hello_osgi\";\n\n protected void activate(ComponentContext componentContext) {\n\n s_logger.info(\"Bundle \" + APP_ID + \" has started!\");\n\n s_logger.debug(APP_ID + \": This is a debug message.\");\n\n }\n\n protected void deactivate(ComponentContext componentContext) {\n\n s_logger.info(\"Bundle \" + APP_ID + \" has stopped!\");\n\n }\n\n}\n
The activate() method is the entry point when the bundle in started. The deactivate() method is the entry point when the bundle is stopped.
Notice the use of the private LoggerFactory.getLogger() method. If the LoggerFactory method is present (running) in the OSGi framework and your hello_osgi bundle is started, your activate method is called, and you can simply access the service by calling the getLogger() method.
One convenient feature of Eclipse, auto-completion, is worth mentioning here. If you type \u2018s_logger.\u2019 (instance name of the \u201cLoggerFactory.getLogger\u201d method) and stop after the period, it will show you a list of methods implemented in that class. The examples above show two different methods used for logging messages. Logger methods include: \u201cerror\u201d, \u201cwarn\u201d, \u201cinfo\u201d, \u201cdebug\u201d, and \u201ctrace\u201d, which represent increasingly lower (more detailed) levels of log information. Logger levels should generally be used to represent the following conditions:
ERROR - A serious problem has occurred that requires attention from the system administrator.
WARNING - An action occurred or a condition was discovered that should be reviewed and may require action before an error occurs. It may also be used for transient issues.
INFO - A report of a normal action or event. This could be a user operation, such as \"login completed\", or an automatic operation, such as a log file rotation.
DEBUG - A debug message used for troubleshooting or performance monitoring. It typically contains detailed event data including things an application developer would need to know.
TRACE - A fairly detailed output of diagnostic logging, such as actual bytes of a particular message being examined.
At this point, there will be errors in your code because of unresolved imports.
Select the menu Source | Organize Imports to resolve these errors. Because you added the \u201corg.slf4j\u201d to your dependency list, you will be prompted to choose one of two potential sources for importing the \u201cLogger\u201d class. Select org.slf4j.Logger and click Finish.
Now the errors in the class should have been resolved. Save the HelloOsgi class.
The complete set of code (with import statements) is shown below.
package org.eclipse.kura.example.hello_osgi;\n\nimport org.osgi.service.component.ComponentContext;\n\nimport org.slf4j.Logger;\n\nimport org.slf4j.LoggerFactory;\n\npublic class HelloOsgi {\n\n private static final Logger s_logger = LoggerFactory.getLogger(HelloOsgi.class);\n\n private static final String APP_ID = \"org.eclipse.kura.example.hello_osgi\";\n\n protected void activate(ComponentContext componentContext) {\n\n s_logger.info(\"Bundle \" + APP_ID + \" has started!\");\n\n s_logger.debug(APP_ID + \": This is a debug message.\");\n\n }\n\n protected void deactivate(ComponentContext componentContext) {\n\n s_logger.info(\"Bundle \" + APP_ID + \" has stopped!\");\n\n }\n\n}\n
For more information on using the Simple Logging Facade for Java (slf4j), see the Logger API.
Switch back to the Manifest Editor. Under Automated Management of Dependencies, ensure the Import-Package option button is selected. Click the add dependencies link to automatically add packages to the dependencies list based on the \u201cimport\u201d statements in your example code. Save changes to the Manifest again.
"},{"location":"java-application-development/hello-world-application/#create-component-class","title":"Create Component Class","text":"Right-click the example project and select New | Other. From the wizard, select Plug-in Development | Component Definition and click Next.
Warning
This option is available only if the Plug-in Development Environment (PDE) is installed in Eclipse (plugins can be installed into Eclipse IDE by searching the name in the Eclipse Marketplace under the Help menu).
In the Class field of the New Component Definition window shown below, click Browse.
Enter the name of your newly created class in the Select entries field. In this case, type the word \u201chello\u201d, and you will see a list of matching items. Select the HelloOsgi class and click OK.
In the Enter or select the parent folder field of the New Component Definition window, add \"/OSGI-INF\" to the existing entry (e.g., org.eclipse.kura.example.hello_osgi/OSGI-INF). Then click Finish.
After the Component class has been created, it will open in the Workspace. In the Overview tab, the Name and Class point to our Java class. Set the Activate field to activate and set the Deactivate field to deactivate. Doing so tells the component where these OSGi activation methods are located. Then save the Component class definition file.
"},{"location":"java-application-development/hello-world-application/#deploying-the-plug-in","title":"Deploying the Plug-in","text":"The next few sections describe how to create a stand-alone JAR file as a deployable OSGI plug-in and how to create an installable Deployment Package.
An OSGi bundle is a Java archive file containing Java code, resources, and a Manifest.
A Deployment Package is a set of resources grouped into a single package file that may be deployed in the OSGi framework through the Deployment Admin service and may contain one or more bundles, configuration objects, etc.
"},{"location":"java-application-development/hello-world-application/#export-the-osgi-bundle","title":"Export the OSGi Bundle","text":"Your bundle can be built as a stand-alone OSGi plug-in.
To do so, right-click the project and select the Export menu. This is equivalent to running javac on your project. From the wizard, select Plug-in Development | Deployable plug-ins and fragments and click Next.
Under Available Plug-ins and Fragments of the Export window, ensure the newly created plug-in is selected. Under Destination, select the Directory option button and use the Browse button to select an appropriate place to save the JAR file on the local file system.
NOTE: During the deployment process that is described in the following section, you will need to remember the location where this JAR file is saved.
Click Finish.
This will create a JAR file in the selected directory (e.g., /home/joe/myPlugins/plugins/org.eclipse.kura.example.hello_osgi_1.0.0.jar).
"},{"location":"java-application-development/hello-world-application/#create-a-deployment-package","title":"Create a Deployment Package","text":"Rather than creating a stand-alone plug-in, you can also create a Deployment Package that contains multiple bundles, configuration elements, etc. that can be deployed into an OSGi framework. In this example, you will simply create a Deployment Package containing the \u201chello_osgi\u201d bundle. This step requires mToolkit to be installed. (See Kura Setup for instructions on setting up the Eclipse development environment.)
Right-click the project and select New | Folder. Select the org.eclipse.kura.example.hello_osgi project and enter a folder named \u201cresources\u201d.
Then repeat this step to create a folder named \u201cdp\u201d under the resources folder. The resources/dp folder will be used to store the Deployment Package.
Select File | New | Other. Select OSGi | Deployment Package Definition and click Next.
Ensure that the Target folder field of the New dpp file window is set to the /[project_name]/resources/dp folder. In the File name field, enter the name for the new Deployment Package file to create, such as \u201chello_osgi\u201d. A version number can also be entered in the Version field. Then click Finish.
Under the resources/dp folder in your project, verify that the [filename].dpp file was created. This is a Deployment Package Project that provides information needed to create the Deployment Package, such as its output directory, ant build file, etc.
Select the Bundles tab and then click New. In the Bundle Path column, select the browse icon. Browse to the bundle\u2019s JAR file created earlier. Select the file and click Open. Doing so should populate the remaining columns as needed.
Save changes to the deployment package file.
In the resources/dp folder, right-click the .dpp file. Select Quick Build. A new [filename].dp file will be created in the same directory. This is the final Deployment Package that can be installed on a remote target system.
In conclusion, you were able to create a new bundle from scratch, write the Java code and Activator, modify the Manifest, and build the plug-in and/or Deployment Package that can be used in a Kura environment.
The next steps will be to test your code in an Emulation mode and/or to deploy your code to a target system running Kura. See Testing and Deploying Bundles to continue with those steps.
"},{"location":"java-application-development/how-to-manage-network-settings/","title":"How to manage Network Settings","text":"This section provides an example of how to create a Kura bundle that can be used to configure the network interfaces of your device. In this example, you will learn how to perform the following functions:
Create a plugin that configures the network interfaces
Connect to a wireless access point
Create a wireless access point
As written, the example code configures the device with a static Wi-Fi configuration. Typically, the device settings would be defined through the Kura Gateway Administration Console instead of through Java code.
A more practical application of this example is for IP network interfaces that need to be dynamically modified based on some external trigger or condition, such as geo-fencing. The Kura framework allows the device to be programmatically changed via its APIs based on application-specific logic.
"},{"location":"java-application-development/how-to-manage-network-settings/#prerequisites","title":"Prerequisites","text":"Setting up the Eclipse Kura Development Environment
"},{"location":"java-application-development/how-to-manage-network-settings/#network-configuration-with-kura","title":"Network Configuration with Kura","text":""},{"location":"java-application-development/how-to-manage-network-settings/#hardware-setup","title":"Hardware Setup","text":"This example requires an embedded device running Kura with at least one Ethernet port and Wi-Fi support.
Additionally, the Connect to an Access Point section requires a wireless access point and the following information about the access point:
SSID (Network Name)
Security Type (WEP, WPA, or WPA2), if any
Password/Passphrase, if any
Lastly, the Create an Access Point section requires:
A wireless device, such as a laptop, to test the access point.
Optionally, you may connect the Kura device\u2019s Ethernet port to another network and use Kura as a gateway to that network.
In order to determine your network interfaces, run one of the following commands at a terminal on the embedded gateway:
ifconfig -a
or ip link show
Typical network interfaces will appear as follows:
lo - loopback interface
eth0 - first Ethernet network interface
wlan0 - first wireless network interface
ppp0 - first point-to-point protocol network interface, which could be a dial-up modem, PPTP VPN connection, cellular modem, etc.
Make note of your wireless interface. For this tutorial, we will assume the wireless interface name is \u2018wlan0\u2019.
"},{"location":"java-application-development/how-to-manage-network-settings/#kura-networking-api","title":"Kura Networking API","text":"The networking API consists of two basic services: org.eclipse.kura.net.NetworkService
and org.eclipse.kura.net.NetworkAdminService
.
The NetworkService is used to get the current state of the network. For example, the getNetworkInterfaces() method will return a List of NetInterface objects (such as EthernetInterface or WifiInterface) for each interface. This provides a detailed representation of the current state of that interface, such as its type, whether it is currently up, and its current address, which is returned by the getNetInterfaceAddresses() method as a List of NetInterfaceAddress objects. The NetworkService can also be used to get a list of all the network interface names available on the system, or a list of all the Wi-Fi access points that are currently detected by the system.
The NetworkAdminService is used to get and set the configuration for each interface. Similar to the NetworkService, it has a getNetworkInterfaceConfigs() that returns a List of NetInterfaceConfig objects (such as EthernetInterfaceConfig and WifiInterfaceConfig) for each interface. These have the same methods as a NetInterface object but represent the current configuration for that interface. For a NetInterfaceConfig object, the getNetInterfaceAddress() method will return a List of NetInterfaceAddressConfig objects. These NetInterfaceAddressConfig instances, in turn, contain a List of NetConfig objects that define the configuration for that interface.
There are many types of NetConfig objects, including:
NetConfigIP4 - contains the IPv4 address configuration
WifiConfig - contains the Wi-Fi configuration. Note that a WifiInterfaceAddressConfig may contain multiple WifiConfigs, since a configuration might exist for one or more Wi-Fi modes. The currently active WifiConfig is the one with a WifiMode that matches the WifiInterfaceAddressConfig WifiMode.
DhcpServerConfigIP4 - contains the IPv4-based DHCP server configuration
DnsServerConfigIP4 - contains the IPv4-based DNS server configuration
FirewallNatConfig - contains the firewall NAT configuration
These NetConfigs can also be used to configure an interface by providing them as a list to the updateEthernetInterfaceConfig()
, updateWifiInterfaceConfig()
, or updateModemInterfaceConfig()
methods in the NetworkAdminService.
In this section, you will develop a Kura network configuration bundle that sets up the Wi-Fi interface as a client to a wireless access point.
"},{"location":"java-application-development/how-to-manage-network-settings/#implement-the-bundle","title":"Implement the Bundle","text":"To implement the network configuration bundle, perform the following steps:
Note
For more detailed information about bundle development (i.e., the plug-in project, classes, and MANIFEST file configuration), please refer to the Hello World Application
Create a Plug-in Project named org.eclipse.kura.example.network
; set the an OSGi framework option to standard; uncheck the Generate an activator option; and set the Execution Environment variable to match the JVM on your target device.
Include the following bundles in the MANIFEST.MF:
org.slf4j
Create a class named NetworkConfigExample in the org.eclipse.kura.example.network project.
Create an OSGI-INF folder in the org.eclipse.kura.example.network project. Add a Component Class with the parent folder org.eclipse.kura.example.network/OSGI-INF, Component Name org.eclipse.kura.example.network, and Class org.eclipse.kura.example.network.NetworkConfigExample.
Select the Services tab in the component.xml file. Under Referenced Services, add org.eclipse.kura.net.NetworkAdminService. Edit the properties of this service, and configure the Bind property to setNetworkAdminService and Unbind to unsetNetworkAdminService as shown in the following screen capture. These settings are required because of the dependency on NetworkAdminService.
The following source code will also need to be implemented:
META-INF/MANIFEST.MF - OSGI manifest that describes the bundle and its dependencies.
OSGI-INF/component.xml - declarative services definition describing what services are exposed by and consumed by this bundle.
org.eclipse.kura.example.network.NetworkConfigExample.java - main implementation class.
The META-INF/MANIFEST.MF file should look as follows when complete:
Warning
Whitespace is significant in this file; make sure yours matches this file exactly.
Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Network\nBundle-SymbolicName: org.eclipse.kura.example.network\nBundle-Version: 1.0.0.qualifier\nBundle-Vendor: ECLIPSE\nBundle-RequiredExecutionEnvironment: JavaSE-1.7\nImport-Package: org.eclipse.kura,\n org.eclipse.kura.net,\n org.eclipse.kura.net.dhcp,\n org.eclipse.kura.net.firewall,\n org.eclipse.kura.net.wifi,\n org.osgi.service.component;version=\"1.2.0\",\n org.slf4j;version=\"1.6.4\"\nService-Component: OSGI-INF/component.xml\n
"},{"location":"java-application-development/how-to-manage-network-settings/#osgi-infcomponentxml-file","title":"OSGI-INF/component.xml File","text":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\"\n name=\"org.eclipse.kura.example.network.NetworkConfigExample\"\n activate=\"activate\"\n deactivate=\"deactivate\"\n enabled=\"true\"\n immediate=\"true\"\n configuration-policy=\"require\"\n modified=\"updated\">\n <implementation class=\"org.eclipse.kura.example.network.NetworkConfigExample\"/>\n <service>\n <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n </service>\n <reference name=\"NetworkAdminService\"\n interface=\"org.eclipse.kura.net.NetworkAdminService\"\n policy=\"static\"\n cardinality=\"1..1\"\n bind=\"setNetworkAdminService\"\n unbind=\"unsetNetworkAdminService\"/>\n <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.example.network.NetworkConfigExample\"/>\n</scr:component>\n
"},{"location":"java-application-development/how-to-manage-network-settings/#orgeclipsekuraexamplenetworknetworkconfigexamplejava","title":"org.eclipse.kura.example.network.NetworkConfigExample.java","text":"package org.eclipse.kura.example.network;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.net.IP4Address;\nimport org.eclipse.kura.net.IPAddress;\nimport org.eclipse.kura.net.NetConfig;\nimport org.eclipse.kura.net.NetConfigIP4;\nimport org.eclipse.kura.net.NetInterfaceStatus;\nimport org.eclipse.kura.net.NetworkAdminService;\nimport org.eclipse.kura.net.dhcp.DhcpServerConfigIP4;\nimport org.eclipse.kura.net.firewall.FirewallNatConfig;\nimport org.eclipse.kura.net.wifi.WifiCiphers;\nimport org.eclipse.kura.net.wifi.WifiConfig;\nimport org.eclipse.kura.net.wifi.WifiMode;\nimport org.eclipse.kura.net.wifi.WifiRadioMode;\nimport org.eclipse.kura.net.wifi.WifiSecurity;\n\npublic class NetworkConfigExample {\n\n private static final Logger s_logger = LoggerFactory.getLogger(NetworkConfigExample.class);\n\n private NetworkAdminService m_netAdminService;\n\n // ----------------------------------------------------------------\n //\n // Dependencies\n //\n // ----------------------------------------------------------------\n\n public void setNetworkAdminService(NetworkAdminService netAdminService) {\n this.m_netAdminService = netAdminService;\n }\n\n public void unsetNetworkAdminService(NetworkAdminService netAdminService) {\n this.m_netAdminService = null;\n }\n\n\n // ----------------------------------------------------------------\n //\n // Activation APIs\n //\n // ----------------------------------------------------------------\n\n protected void activate(ComponentContext componentContext) {\n s_logger.info(\"Activating NetworkConfigExample...\");\n\n connectToWirelessAccessPoint();\n// createWirelessAccessPoint();\n\n s_logger.info(\"Activating NetworkConfigExample... Done.\");\n }\n\n protected void deactivate(ComponentContext componentContext) {\n s_logger.info(\"Deactivating NetworkConfigExample...\");\n\n s_logger.info(\"Deactivating NetworkConfigExample... Done.\");\n }\n\n\n // ----------------------------------------------------------------\n //\n // Private Methods\n //\n // ----------------------------------------------------------------\n\n /**\n * Connect to a wireless access point using the hard-coded parameters below\n */\n private void connectToWirelessAccessPoint() {\n String interfaceName = \"wlan0\";\n\n // Create a NetConfigIP4 - configure as a WAN (gateway) interface, and a DHCP client\n NetInterfaceStatus netInterfaceStatus = NetInterfaceStatus.netIPv4StatusEnabledWAN;\n boolean dhcpClient = true;\n boolean autoConnect = true;\n NetConfigIP4 netConfigIP4 = new NetConfigIP4(netInterfaceStatus, autoConnect, dhcpClient);\n\n // Create a WifiConfig managed mode client\n String driver = \"nl80211\";\n String ssid = \"access_point_ssid\";\n String password = \"password\";\n WifiSecurity security = WifiSecurity.SECURITY_WPA2;\n WifiCiphers ciphers = WifiCiphers.CCMP_TKIP;\n int[] channels = {1,2,3,4,5,6,7,8,9,10,11};\n\n WifiConfig wifiConfig = new WifiConfig();\n wifiConfig.setMode(WifiMode.INFRA);\n wifiConfig.setDriver(driver);\n wifiConfig.setSSID(ssid);\n wifiConfig.setPasskey(password);\n wifiConfig.setSecurity(security);\n wifiConfig.setChannels(channels);\n wifiConfig.setGroupCiphers(ciphers);\n wifiConfig.setPairwiseCiphers(ciphers);\n\n // Create a NetConfig List\n List<NetConfig> netConfigs = new ArrayList<NetConfig>();\n netConfigs.add(netConfigIP4);\n netConfigs.add(wifiConfig);\n\n // Configure the interface\n try{\n s_logger.info(\"Reconfiguring \" + interfaceName + \" to connect to \" + ssid);\n m_netAdminService.disableInterface(interfaceName);\n m_netAdminService.updateWifiInterfaceConfig(interfaceName, autoConnect, null, netConfigs);\n\n s_logger.info(\"Enable \" + interfaceName);\n m_netAdminService.enableInterface(interfaceName, dhcpClient);\n } catch(KuraException e) {\n s_logger.error(\"Error connecting to wireless access point\", e);\n }\n }\n\n /**\n * Create a wireless access point\n */\n private void createWirelessAccessPoint() {\n try{\n String interfaceName = \"wlan0\";\n\n // Create a NetConfigIP4 - configure as a LAN interface with a manual IP address\n NetInterfaceStatus netInterfaceStatus = NetInterfaceStatus.netIPv4StatusEnabledLAN;\n boolean dhcpClient = false;\n boolean autoConnect = true;\n IP4Address ipAddress = (IP4Address) IPAddress.parseHostAddress(\"172.16.10.1\");\n IP4Address subnetMask = (IP4Address) IPAddress.parseHostAddress(\"255.255.255.0\");\n\n NetConfigIP4 netConfigIP4 = new NetConfigIP4(netInterfaceStatus, autoConnect);\n netConfigIP4.setAddress(ipAddress);\n netConfigIP4.setSubnetMask(subnetMask);\n\n // Create a WifiConfig access point\n String driver = \"nl80211\";\n String ssid = \"NetworkConfigExample\";\n String password = \"password\";\n WifiSecurity security = WifiSecurity.SECURITY_WPA2;\n WifiCiphers ciphers = WifiCiphers.CCMP_TKIP;\n int[] channels = {1};\n WifiRadioMode radioMode = WifiRadioMode.RADIO_MODE_80211g;\n String hwMode = \"g\";\n\n WifiConfig wifiConfig = new WifiConfig();\n wifiConfig.setMode(WifiMode.MASTER);\n wifiConfig.setDriver(driver);\n wifiConfig.setSSID(ssid);\n wifiConfig.setPasskey(password);\n wifiConfig.setSecurity(security);\n wifiConfig.setChannels(channels);\n wifiConfig.setGroupCiphers(ciphers);\n wifiConfig.setPairwiseCiphers(ciphers);\n wifiConfig.setRadioMode(radioMode);\n wifiConfig.setHardwareMode(hwMode);\n\n\n // Create a DhcpServerConfig to enable DHCP server functionality\n int defaultLeaseTime = 7200;\n int maximumLeaseTime = 7200;\n IP4Address routerAddress = ipAddress;\n IP4Address rangeStart = (IP4Address) IPAddress.parseHostAddress(\"172.16.10.100\");\n IP4Address rangeEnd = (IP4Address) IPAddress.parseHostAddress(\"172.16.10.200\");\n IP4Address dhcpSubnetMask = (IP4Address) IPAddress.parseHostAddress(\"255.255.255.0\");\n IP4Address subnet = (IP4Address) IPAddress.parseHostAddress(\"172.16.10.0\");\n short prefix = 24;\n boolean passDns = true;\n\n List<IP4Address> dnsServers = new ArrayList<IP4Address>();\n dnsServers.add(ipAddress); // Use our IP as the DNS server\n\n DhcpServerConfigIP4 dhcpServerConfigIP4 = new DhcpServerConfigIP4(\n interfaceName, true, subnet, routerAddress, dhcpSubnetMask, defaultLeaseTime,\n maximumLeaseTime, prefix, rangeStart, rangeEnd, passDns, dnsServers);\n\n // Create a FirewallNatConfig to enable NAT (network address translation)\n // note that the destination interface is determined dynamically\n FirewallNatConfig natConfig = new FirewallNatConfig(interfaceName, \"tbd\", true);\n\n\n // Create a NetConfig List\n List<NetConfig> netConfigs = new ArrayList<NetConfig>();\n netConfigs.add(netConfigIP4);\n netConfigs.add(wifiConfig);\n netConfigs.add(dhcpServerConfigIP4);\n netConfigs.add(natConfig);\n\n // Configure the interface\n s_logger.info(\"Reconfiguring \" + interfaceName + \" as an access point with SSID: \" + ssid);\n m_netAdminService.disableInterface(interfaceName);\n m_netAdminService.updateWifiInterfaceConfig(interfaceName, autoConnect, null, netConfigs);\n\n s_logger.info(\"Enable \" + interfaceName);\n m_netAdminService.enableInterface(interfaceName, dhcpClient);\n } catch(Exception e) {\n s_logger.error(\"Error configuring as an access point\", e);\n }\n }\n}\n
Modify the parameters in the connectToWirelessAccessPoint() method with the specific values for the access point you want to connect to, including the variables for SSID, password, and security settings:
String ssid = \"access_point_ssid\";
String password = \"password\";
WifiSecurity security = WifiSecurity.SECURITY_WPA2;
At this point, the bundle implementation is complete. Make sure to save all files before proceeding.
Export the OSGi bundle as a stand-alone plug-in, following the instructions in Hello World Using the Kura Logger.
"},{"location":"java-application-development/how-to-manage-network-settings/#deploy-the-bundle","title":"Deploy the Bundle","text":"In order to proceed, you need to know the IP address of your embedded gateway that is running Kura. Follow the mToolkit instructions for installing a single bundle to the remote target device located here. Once the bundle has finished deploying, it will set the device\u2019s network configuration and attempt to connect to a Wi-Fi access point using the configured parameters in the connectToWirelessAccessPoint() method.
"},{"location":"java-application-development/how-to-manage-network-settings/#test-the-connection-to-the-access-point","title":"Test the Connection to the Access Point","text":"To verify that the interface (wlan0) has acquired an IP address, run the ifconfig command at a terminal on the embedded gateway.
To show the current connection status to the access point, run the following commands:
wpa_cli -i wlan0 status\niw dev wlan0 link\niw dev wlan0 station dump\n
"},{"location":"java-application-development/how-to-manage-network-settings/#create-an-access-point","title":"Create an Access Point","text":"This example code can be modified slightly to make the gateway function as an access point instead of connecting to an access point.
To do this, modify the activate() method in the NetworkConfigExample.java file to comment out connectToWirelessAccessPoint()
and uncomment createWirelessAccessPoint()
.
protected void activate(ComponentContext componentContext) {\n s_logger.info(\"Activating NetworkConfigExample...\");\n\n// connectToWirelessAccessPoint();\n createWirelessAccessPoint();\n\n s_logger.info(\"Activating NetworkConfigExample... Done.\");\n}\n
Modify the access point configuration variables under createWirelessAccessPoint() for your needs, if necessary, such as the variables:
IP4Address ipAddress = (IP4Address) IPAddress.parseHostAddress(\"172.16.10.1\");\nIP4Address subnetMask = (IP4Address) IPAddress.parseHostAddress(\"255.255.255.0\");\n\n// Create a WifiConfig access point\nString driver = \"nl80211\";\nString ssid = \"NetworkConfigExample\";\nString password = \"password\";\n
Export the bundle again as a stand-alone OSGi plug-in and redeploy it to the target device. It should now reconfigure itself to create an access point with an active DHCP server, DNS proxy forwarding, and NAT enabled.
"},{"location":"java-application-development/how-to-manage-network-settings/#test-the-access-point","title":"Test the Access Point","text":"To verify that the interface (wlan0) has a fixed IP address, run the ifconfig command at a terminal on the embedded gateway.
To view information on the Wi-Fi access point, including interface name, wireless channel, and MAC address, enter:
iw dev wlan0 info
To monitor connect and disconnect events from the access point, enter:
iw event \u2013f
Use another wireless client, such as a laptop, to verify that you can connect to the access point, that it receives an IP address, and that it can ping the network. When the client connects to the access point, the console should show a new station connection event.
To view station statistic information, including signal strength and bitrate, enter:
iw dev wlan0 station dump
Optionally, if the gateway has another interface configured for WAN with connection to the Internet, then the wireless client should be able to reach the Internet using this access point as its gateway. The setup for the other interface (not covered in this example) would need to be configured in the device using the Kura Gateway Administration Console.
"},{"location":"java-application-development/how-to-serial-ports/","title":"How to Use Serial Ports","text":""},{"location":"java-application-development/how-to-serial-ports/#overview","title":"Overview","text":"This section provides an example of how to create a Kura bundle that will communicate with a serial device. In this example, you will communicate with a simple terminal emulator to demonstrate both transmitting and receiving data. You will learn how to perform the following functions:
Create a plugin that communicates to serial devices
Export the bundle
Install the bundle on the remote device
Test the communication with minicom where, minicom is acting as an attached serial device such as an NFC reader, GPS device, or some other ASCII-based communication device
Setting up Kura Development Environment
Hello World Using the Kura Logger
Hardware
Use an embedded device running Kura with two available serial ports. (If the device does not have a serial port, USB to serial adapters can be used.)
Ensure minicom is installed on the embedded device.
This section of the tutorial covers setting up the hardware, determining serial port device nodes, implementing the basic serial communication bundle, deploying the bundle, and validating its functionality. After completing this section, you should be able to communicate with any ASCII-based serial device attached to a Kura-enabled embedded gateway. In this example, we are using ASCII for clarity, but these same techniques can be used to communicate with serial devices that communicate using binary protocols.
"},{"location":"java-application-development/how-to-serial-ports/#hardware-setup","title":"Hardware Setup","text":"Your setup requirements will depend on your hardware platform. At a minimum, you will need two serial ports with a null modem serial, crossover cable connecting them.
If your platform has integrated serial ports, you only need to connect them using a null modem serial cable.
If you do not have integrated serial ports on your platform, you will need to purchase USB-to-Serial adapters. It is recommended to use a USB-to-Serial adapter with either the PL2303 or FTDI chipset, but others may work depending on your hardware platform and underlying Linux support. Once you have attached these adapters to your device, you can attach the null modem serial cable between the two ports.
This step is hardware specific. If your hardware device has integrated serial ports, contact your hardware device manufacturer or review the documentation to find out how the ports are named in the operating system. The device identifiers should be similar to the following:
/dev/ttyS*xx*\n/dev/ttyUSB*xx*\n/dev/ttyACM*xx*\n
If you are using USB-to-Serial adapters, Linux usually allocates the associated device nodes dynamically at the time of insertion. In order to determine what they are, run the following command at a terminal on the embedded gateway:
tail -f /var/log/syslog\n
Warning
Depending on your specific Linux implementation, other possible log files may be: /var/log/kern.log, /var/log/kernel, or /var/log/dmesg.
With the above command running, insert your USB-to-Serial adapter. You should see output similar to the following:
root@localhost:/root> tail -f /var/log/syslog\nAug 15 18:43:47 localhost kernel: usb 3-2: new full speed USB device using uhci_hcd and address 3\nAug 15 18:43:47 localhost kernel: pl2303 3-2:1.0: pl2303 converter detected\nAug 15 18:43:47 localhost kernel: usb 3-2: pl2303 converter now attached to ttyUSB10\n
In this example, our device is a PL2303-compatible device and is allocated a device node of \u201c/dev/ttyUSB10\u201d. While your results may differ, the key is to identify the \u201ctty\u201d device that was allocated. For the rest of this tutorial, this device will be referred to as [device_node_1], which in this example is /dev/ttyUSB10. During development, it is also important to keep in mind that these values are dynamic; therefore, from one boot to the next and one insertion to the next, these values may change. To stop \u2018tail\u2019 from running in your console, escape with \u2018 c\u2019.
If you are using two USB-to-Serial adapters, repeat the above procedure for the second serial port. The resulting device node will be referred to as [device_node_2].
"},{"location":"java-application-development/how-to-serial-ports/#implement-the-bundle","title":"Implement the Bundle","text":"Now that you have two serial ports connected to each other, you are ready to implement the code. You will use the same general method that is described in section Hello World Application with the following exceptions:
The following files need to be implemented:
META-INF/MANIFEST.MF \u2013 OSGI manifest that describes the bundle and its dependencies
OSGI-INF/component.xml \u2013 declarative services definition that describe what services are exposed and consumed by this bundle
OSGI-INF/metatype/org.eclipse.kura.example.serial.SerialExample.xml \u2013 configuration description of the bundle and its parameters, types, and defaults
org.eclipse.kura.example.serial.SerialExample.java \u2013 main implementation class
The META-INF/MANIFEST.MF file should appear as shown below when complete:
NOTE: Whitespace is significant in this file. Make sure yours matches this file exactly with the exception that RequiredExecutionEnvironment may be JavaSE-1.6 or JavaSE-1.7, depending on the Java installation of your device.
Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Serial\nBundle-SymbolicName: org.eclipse.kura.example.serial\nBundle-Version: 1.0.0.qualifier\nBundle-RequiredExecutionEnvironment: JavaSE-1.7\nService-Component: OSGI-INF/component.xml\nBundle-ActivationPolicy: lazy\nImport-Package: javax.comm;version=\"1.2.0\",\n javax.microedition.io;resolution:=optional,\n org.eclipse.kura.cloud;version=\"0.2.0\",\n org.eclipse.kura.comm;version=\"0.2.0\",\n org.eclipse.kura.configuration;version=\"0.2.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.osgi.service.io;version=\"1.0.0\",\n org.slf4j;version=\"1.6.4\"\nBundle-ClassPath: .\n
In addition, the build.properties file should have org.eclipse.equinox.io listed as an additional bundle similar to below:
additional.bundles = org.eclipse.equinox.io\n
"},{"location":"java-application-development/how-to-serial-ports/#osgi-infcomponentxml-file","title":"OSGI-INF/component.xml File","text":"Warning
Starting from Kura 3.0, the configuration service will only track \"relevant services\" that, in their component description files, will provide the ConfigurableComponent or SelfConfigurableComponent interface. The old behavior can be restored by setting the \"org.eclipse.kura.core.configuration.legacyServiceTracking\" property to true.
If Kura 2.1.0 or older versions are used or the org.eclipse.kura.core.configuration.legacyServiceTracking
system property is set to true, the OSGI-INF/component.xml should appear as shown below when complete:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\"\n name=\"org.eclipse.kura.example.serial.SerialExample\" activate=\"activate\"\n deactivate=\"deactivate\" modified=\"updated\" enabled=\"true\" immediate=\"true\"\n configuration-policy=\"require\">\n\n <implementation class=\"org.eclipse.kura.example.serial.SerialExample\"/>\n <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.example.serial.SerialExample\"/>\n\n <service>\n <provide interface=\"org.eclipse.kura.example.serial.SerialExample\"/>\n </service>\n <reference bind=\"setConnectionFactory\" cardinality=\"1..1\"\n interface=\"org.osgi.service.io.ConnectionFactory\" name=\"ConnectionFactory\"\n policy=\"static\" unbind=\"unsetConnectionFactory\" />\n</scr:component>\n
If Kura 3.0 or newer versions are used and the org.eclipse.kura.core.configuration.legacyServiceTracking
system property is set to false or not set, the OSGI-INF/component.xml should appear as shown below when complete:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\"\n name=\"org.eclipse.kura.example.serial.SerialExample\" activate=\"activate\"\n deactivate=\"deactivate\" modified=\"updated\" enabled=\"true\" immediate=\"true\"\n configuration-policy=\"require\">\n\n <implementation class=\"org.eclipse.kura.example.serial.SerialExample\"/>\n <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.example.serial.SerialExample\"/>\n\n <service>\n <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n </service>\n <reference bind=\"setConnectionFactory\" cardinality=\"1..1\"\n interface=\"org.osgi.service.io.ConnectionFactory\" name=\"ConnectionFactory\"\n policy=\"static\" unbind=\"unsetConnectionFactory\" />\n</scr:component>\n
"},{"location":"java-application-development/how-to-serial-ports/#osgi-infmetatypeorgeclipsekuraexampleserialserialexamplexml-file","title":"OSGI-INF/metatype/org.eclipse.kura.example.serial.SerialExample.xml File","text":"The OSGI-INF/metatype/org.eclipse.kura.example.serial.SerialExample.xml file should appear as shown below when complete:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n <OCD id=\"org.eclipse.kura.example.serial.SerialExample\"\n name=\"SerialExample\"\n description=\"Example of a Configuring KURA Application echoing data read from the serial port.\">\n\n <Icon resource=\"http://sphotos-a.xx.fbcdn.net/hphotos-ash4/p480x480/408247_10151040905591065_1989684710_n.jpg\" size=\"32\"/>\n\n <AD id=\"serial.device\"\n name=\"serial.device\"\n type=\"String\"\n cardinality=\"0\"\n required=\"false\"\n description=\"Name of the serial device (e.g. /dev/ttyS0, /dev/ttyACM0, /dev/ttyUSB0).\"/>\n\n <AD id=\"serial.baudrate\"\n name=\"serial.baudrate\"\n type=\"String\"\n cardinality=\"0\"\n required=\"true\"\n default=\"9600\"\n description=\"Baudrate.\">\n <Option label=\"9600\" value=\"9600\"/>\n <Option label=\"19200\" value=\"19200\"/>\n <Option label=\"38400\" value=\"38400\"/>\n <Option label=\"57600\" value=\"57600\"/>\n <Option label=\"115200\" value=\"115200\"/>\n </AD>\n\n <AD id=\"serial.data-bits\"\n name=\"serial.data-bits\"\n type=\"String\"\n cardinality=\"0\"\n required=\"true\"\n default=\"8\"\n description=\"Data bits.\">\n <Option label=\"7\" value=\"7\"/>\n <Option label=\"8\" value=\"8\"/>\n </AD>\n\n <AD id=\"serial.parity\"\n name=\"serial.parity\"\n type=\"String\"\n cardinality=\"0\"\n required=\"true\"\n default=\"none\"\n description=\"Parity.\">\n <Option label=\"none\" value=\"none\"/>\n <Option label=\"even\" value=\"even\"/>\n <Option label=\"odd\" value=\"odd\"/>\n </AD>\n\n <AD id=\"serial.stop-bits\"\n name=\"serial.stop-bits\"\n type=\"String\"\n cardinality=\"0\"\n required=\"true\"\n default=\"1\"\n description=\"Stop bits.\">\n <Option label=\"1\" value=\"1\"/>\n <Option label=\"2\" value=\"2\"/>\n </AD>\n\n </OCD>\n <Designate pid=\"org.eclipse.kura.example.serial.SerialExample\">\n <Object ocdref=\"org.eclipse.kura.example.serial.SerialExample\"/>\n </Designate>\n</MetaData>\n
"},{"location":"java-application-development/how-to-serial-ports/#orgeclipsekuraexampleserialserialexamplejava-file","title":"org.eclipse.kura.example.serial.SerialExample.java File","text":"The org.eclipse.kura.example.serial.SerialExample.java file should appear as shown below when complete:
package org.eclipse.kura.example.serial;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.ScheduledThreadPoolExecutor;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.io.ConnectionFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class SerialExample implements ConfigurableComponent {\n\n private static final Logger s_logger = LoggerFactory.getLogger(SerialExample.class);\n\n private static final String SERIAL_DEVICE_PROP_NAME= \"serial.device\";\n private static final String SERIAL_BAUDRATE_PROP_NAME= \"serial.baudrate\";\n private static final String SERIAL_DATA_BITS_PROP_NAME= \"serial.data-bits\";\n private static final String SERIAL_PARITY_PROP_NAME= \"serial.parity\";\n private static final String SERIAL_STOP_BITS_PROP_NAME= \"serial.stop-bits\";\n\n private ConnectionFactory m_connectionFactory;\n private CommConnection m_commConnection;\n private InputStream m_commIs;\n private OutputStream m_commOs;\n private ScheduledThreadPoolExecutor m_worker;\n private Future<?> m_handle;\n private Map<String, Object> m_properties;\n\n // ----------------------------------------------------------------\n //\n // Dependencies\n //\n // ----------------------------------------------------------------\n public void setConnectionFactory(ConnectionFactory connectionFactory) {\n this.m_connectionFactory = connectionFactory;\n }\n\n public void unsetConnectionFactory(ConnectionFactory connectionFactory) {\n this.m_connectionFactory = null;\n }\n\n // ----------------------------------------------------------------\n //\n // Activation APIs\n //\n // ----------------------------------------------------------------\n\n protected void activate(ComponentContext componentContext, Map<String,Object> properties) {\n s_logger.info(\"Activating SerialExample...\");\n\n m_worker = new ScheduledThreadPoolExecutor(1);\n m_properties = new HashMap<String, Object>();\n doUpdate(properties);\n s_logger.info(\"Activating SerialExample... Done.\");\n }\n\n protected void deactivate(ComponentContext componentContext) {\n s_logger.info(\"Deactivating SerialExample...\");\n\n // shutting down the worker and cleaning up the properties\n m_handle.cancel(true);\n m_worker.shutdownNow();\n //close the serial port\n closePort();\n s_logger.info(\"Deactivating SerialExample... Done.\");\n }\n\n public void updated(Map<String,Object> properties) {\n s_logger.info(\"Updated SerialExample...\");\n\n doUpdate(properties);\n s_logger.info(\"Updated SerialExample... Done.\");\n }\n\n // ----------------------------------------------------------------\n //\n // Private Methods\n //\n // ----------------------------------------------------------------\n\n /**\n * Called after a new set of properties has been configured on the service\n */\n private void doUpdate(Map<String, Object> properties) {\n try {\n for (String s : properties.keySet()) {\n s_logger.info(\"Update - \"+s+\": \"+properties.get(s));\n }\n\n // cancel a current worker handle if one if active\n if (m_handle != null) {\n m_handle.cancel(true);\n }\n\n //close the serial port so it can be reconfigured\n closePort();\n\n //store the properties\n m_properties.clear();\n m_properties.putAll(properties);\n\n //reopen the port with the new configuration\n openPort();\n\n //start the worker thread\n m_handle = m_worker.submit(new Runnable() {\n @Override\n public void run() {\n doSerial();\n }\n });\n\n } catch (Throwable t) {\n s_logger.error(\"Unexpected Throwable\", t);\n }\n }\n\n private void openPort() {\n String port = (String) m_properties.get(SERIAL_DEVICE_PROP_NAME);\n\n if (port == null) {\n s_logger.info(\"Port name not configured\");\n return;\n }\n\n int baudRate = Integer.valueOf((String) m_properties.get(SERIAL_BAUDRATE_PROP_NAME));\n int dataBits = Integer.valueOf((String) m_properties.get(SERIAL_DATA_BITS_PROP_NAME));\n int stopBits = Integer.valueOf((String) m_properties.get(SERIAL_STOP_BITS_PROP_NAME));\n String sParity = (String) m_properties.get(SERIAL_PARITY_PROP_NAME);\n int parity = CommURI.PARITY_NONE;\n\n if (sParity.equals(\"none\")) {\n parity = CommURI.PARITY_NONE;\n } else if (sParity.equals(\"odd\")) {\n parity = CommURI.PARITY_ODD;\n } else if (sParity.equals(\"even\")) {\n parity = CommURI.PARITY_EVEN;\n }\n\n String uri = new CommURI.Builder(port)\n .withBaudRate(baudRate)\n .withDataBits(dataBits)\n .withStopBits(stopBits)\n .withParity(parity)\n .withTimeout(1000)\n .build().toString();\n\n try {\n m_commConnection = (CommConnection) m_connectionFactory.createConnection(uri, 1, false);\n m_commIs = m_commConnection.openInputStream();\n m_commOs = m_commConnection.openOutputStream();\n s_logger.info(port+\" open\");\n } catch (IOException e) {\n s_logger.error(\"Failed to open port \" + port, e);\n cleanupPort();\n }\n }\n\n private void cleanupPort() {\n\n if (m_commIs != null) {\n try {\n s_logger.info(\"Closing port input stream...\");\n m_commIs.close();\n s_logger.info(\"Closed port input stream\");\n } catch (IOException e) {\n s_logger.error(\"Cannot close port input stream\", e);\n }\n m_commIs = null;\n }\n\n if (m_commOs != null) {\n try {\n s_logger.info(\"Closing port output stream...\");\n m_commOs.close();\n s_logger.info(\"Closed port output stream\");\n } catch (IOException e) {\n s_logger.error(\"Cannot close port output stream\", e);\n }\n m_commOs = null;\n }\n\n if (m_commConnection != null) {\n try {\n s_logger.info(\"Closing port...\");\n m_commConnection.close();\n s_logger.info(\"Closed port\");\n } catch (IOException e) {\n s_logger.error(\"Cannot close port\", e);\n }\n m_commConnection = null;\n }\n }\n\n private void closePort() {\n cleanupPort();\n }\n\n private void doSerial() {\n if (m_commIs != null) {\n try {\n int c = -1;\n StringBuilder sb = new StringBuilder();\n while (m_commIs != null) {\n if (m_commIs.available() != 0) {\n c = m_commIs.read();\n } else {\n try {\n Thread.sleep(100);\n continue;\n } catch (InterruptedException e) {\n return;\n }\n }\n\n // on reception of CR, publish the received sentence\n if (c==13) {\n s_logger.debug(\"Received serial input, echoing to output: \" + sb.toString());\n sb.append(\"\\r\\n\");\n String dataRead = sb.toString();\n //echo the data to the output stream\n m_commOs.write(dataRead.getBytes());\n //reset the buffer\n sb = new StringBuilder();\n } else if (c!=10) {\n sb.append((char) c);\n }\n }\n\n } catch (IOException e) {\n s_logger.error(\"Cannot read port\", e);\n } finally {\n try {\n m_commIs.close();\n } catch (IOException e) {\n s_logger.error(\"Cannot close buffered reader\", e);\n }\n }\n }\n }\n}\n
At this point, the bundle implementation is complete. Make sure to save all files before proceeding."},{"location":"java-application-development/how-to-serial-ports/#export-the-bundle","title":"Export the Bundle","text":"To build the Serial Example bundle as a stand-alone OSGi plugin, right-click the project and select Export.
From the wizard, select Plug-in Development | Deployable plug-ins and fragments and click Next.
The Export window appears. Under Available Plug-ins and Fragments, verify that the newly created plug-in is selected.
Under Destination, select the Directory option button and use the Browse button to select an appropriate place to save the JAR file on the local file system.
Info
You will need to know the location where this JAR file is saved for the deployment process.
Under Options, select the checkbox Use class files compiled in the workspace in addition to the checkboxes already enabled, and click Finish.
Doing so will create a JAR file in the selected directory (e.g., /home/joe/myPlugins/plugins/org.eclipse.kura.example.serial_1.0.0.201410311510.jar).
"},{"location":"java-application-development/how-to-serial-ports/#deploy-the-bundle","title":"Deploy the Bundle","text":"In order to proceed, you need to know the IP address of your embedded gateway that is running Kura. Once you have this IP address, follow the mToolkit instructions for installing a single bundle to a remote target device (refer to section 2.03 Testing and Deploying Bundles).
Once the installation successfully completes, you should see a message from the /var/log/kura.log file indicating that the bundle was successfully installed and configured. You can also run this example with the emulator in a Linux or OS X environment as shown sample output below. Make sure that your user account has owner permission for the serial device in /dev.
"},{"location":"java-application-development/how-to-serial-ports/#validate-the-bundle","title":"Validate the Bundle","text":"Next, you need to test that your bundle does indeed echo characters back by opening minicom and configuring it to use [device_node_2] that was previously determined.
Open minicom using the following command at a Linux terminal on the remote gateway device:
minicom -s\n
This command opens a view similar to the following screen capture:
Scroll down to Serial port setup and press . A new dialog window opens as shown below:
Use the minicom menu options on the left (i.e., A, B, C, etc.) to change desired fields. Set the fields to the same values as shown in the previous screen capture except the Serial Device should match the [device_node_2] on your target device. Once this is set, press \\<ENTER> to exit from this menu.
In the main configuration menu, select Exit (do not select the option Exit from Minicom). At this point, you have successfully started minicom on the second serial port attached to your null modem cable allowing minicom to act as a serial device that can send and receive commands to your Kura bundle. You can verify this operation by typing characters and pressing . The function (specifically a \u2018\\n\u2019 character) signals to the Kura application to echo the buffered characters back to the serial device (minicom in this case).
Upon startup, minicom sends an initialization string to the serial device. These characters are sent to the minicom terminal because they were echoed back by Kura listening on the port at the other end of the null modem cable.
When you are done, exit minicom by pressing \u2018 a\u2019, then \u2018q\u2019, and finally \u2018\u2019. Doing so brings you back to the Linux command prompt.
This tutorial instructed you how to write and deploy a Kura bundle on your target device that listens for serial data (coming from the minicom terminal and being received on [device_node_1]). This tutorial also demonstrated that the application echoes data back to the same serial port that is received in minicom, which acts a serial device that sends and receives data. If supported by the device, Kura may send and receive binary data instead of ASCII.
"},{"location":"java-application-development/how-to-use-can-bus/","title":"How to Use CAN bus","text":"The Kura CAN bus protocol implementation is based on the SocketCAN interface, which provides a socket interface to userspace applications. The sockets are designed as can0 and can1. The SocketCAN package is an implementation of Controller Area Network (CAN) protocols. For more information, refer to the following link: https://www.kernel.org/doc/Documentation/networking/can.txt.
"},{"location":"java-application-development/how-to-use-can-bus/#configure-the-can-bus-driver","title":"Configure the CAN bus Driver","text":"The CAN network must be initialized prior to communications. Verify that the CAN driver module has been enabled in the kernel by issuing the following command:
ifconfig -a\n
The connections \u201ccan0\u201d and \u201ccan1\u201d should be displayed. Next, the sockets must be enabled and configured using the following commands (the bitrate value must be set according to the bitrate of the device that will be connected):
ip link set can0 type can bitrate 50000 triple-sampling on\nip link set can0 up\nip link set can1 type can bitrate 50000 triple-sampling on\nip link set can1 up\n
"},{"location":"java-application-development/how-to-use-can-bus/#use-the-can-bus-driver-in-kura","title":"Use the CAN bus Driver in Kura","text":"To use the Can bus Driver in Kura, the bundle org.eclipse.kura.protocol.can must be installed. Refer to the section Application Management for more information.
Once this bundle is installed and verified, the CanConnectionService provides access to basic functionalities of the CAN network, including:
sendCanMessage \u2013 sends an array of bytes in RAW mode.
receiveCanMessage \u2013 reads frames in RAW mode waiting on socket CAN.
Refer to the following Kura javadocs for more information: http://download.eclipse.org/kura/docs/api/5.2.0/apidocs/.
Also, for information about the wrapper that this service utilizes, refer to the following link: https://github.com/entropia/libsocket-can-java.
"},{"location":"java-application-development/how-to-use-dummy-signature-service/","title":"How to use the Dummy Container Signature Validation Service","text":"The Dummy Container Signature Validation Service is an example implementation of the Container Signature Validation Service interface which mainly serves as a reference for future implementations and testing.
The purpose of this component is to have a service whose configuration dictates the signature verification outcome. In the main text area is possible to set the container image reference that the service will report as correctly signed.
The format accepted by the service is: <imageName>:<imageTag>@<imageDigest>
where
<imageName>
: is the container image name. The value will need to be expressed in the form registryURL/imagename in case of a custom registry. Example: nginx
or nvcr.io/nvidia/deepstream
.<imageTag>
: is the container image tag. Example: latest
or 6.4-gc-triton-devel
.<imageDigest>
: is the image digest in the OCI specification format.Each image should be separated by a newline. The service will report a successful signature validation for each image inside its configuration, returning the provided image digest as a result.
"},{"location":"java-application-development/how-to-use-gpio/","title":"How to use GPIO","text":"GPIO resources can be accessed either using the GPIO Service provided by Kura, or directly using the OpenJDK Device I/O embedded library.
"},{"location":"java-application-development/how-to-use-gpio/#gpio-service","title":"GPIO Service","text":"Access to GPIO resources is granted by the GPIOService. Once retrieved, the service can be used to acquire a GPIO Pin and use it as a digital output or a digital input.
The GPIO Service exposes methods to retrieve a GPIO Pin via its name or index as shown below.
KuraGpioPin thePin = gpioServiceInstance.getPinByTerminal(18);\nKuraGpioPin thePin = gpioServiceInstance.getPinByName(\"IgnitionPin\");\n
The KuraGpioPin object is used to manipulate GPIO Pins and exposes methods to read the status of an input, or set the status of digital output as shown below.
//sets digital output value to high\nthePin.setValue(true);\n\n//get value of a digital input pin\nboolean active = thePin.getValue();\n\n//listen for status change on a digital input pin\ntry { \n thePin.addPinStatusListener(new PinStatusListener() {\n @Override \n public void pinStatusChange(boolean value) { \n // Perform tasks when pin status changes \n } \n });\n} catch (KuraClosedDeviceException e) {\n // Here if GPIO cannot be acquired\n } catch (IOException e) {\n // Here on I/O error\n }\n
"},{"location":"java-application-development/how-to-use-gpio/#pin-configuration","title":"Pin Configuration","text":"Pin names, indexes, and configuration are defined in the jdk.dio.properties file.
Although GPIO pins can be accessed with their default configuration, the settings of each pin can be changed when acquiring it with the GPIO Service as shown below.
KuraGpioPin customInputPin = gpioServiceInstance.getPinByTerminal(\n 14, \n KuraGPIODirection.INPUT, \n KuraGPIOMode.INPUT_PULL_UP, \n KuraGPIOTrigger.BOTH_LEVELS);\n
"},{"location":"java-application-development/how-to-use-gpio/#default-configuration","title":"Default Configuration","text":"Default hardware configuration for the hardware platform is defined in the jdk.dio.properties file. Standard configuration for complex devices can be added on a per-device basis as shown below.
#Default PIN configuration. To be overwritten in the following lines\ngpio.GPIOPin = initValue:0, deviceNumber:0, direction:3, mode:-1, trigger:3\n\n#Standard PIN configuration\n64 = deviceType: gpio.GPIOPin, pinNumber:64, name:RELAY1\n
Starting from Kura 5.5.0, the default pin configuration can be described in the form of symbolic links. The syntax is as follows:
/dev/digital_in1 = deviceType: gpio.GPIOPin, direction:0, mode=1, name:digital_in1\n
where /dev/digital_in1
points to /sys/class/gpio/gpioXYZ
. The pin number is set to XYZ and it can be retrieved by name.
Linux-level access in Kura is granted through OpenJDK Device I/O, a third-party library that leverages standard Java ME Device I/O APIs to Java SE. Kura is distributed with the relevant native libraries, together with the default hardware configuration, for each platform on which it runs.
I2C, SPI, and GPIO resources can be directly accessed through the jdk.dio library present in the target platform.
"},{"location":"java-application-development/how-to-use-gpio/#apis","title":"APIs","text":"Kura supports the full set of APIs for the listed device types. Refer to References for further API information.
"},{"location":"java-application-development/how-to-use-gpio/#accessing-a-gpio-pin-with-openjdk-device-io","title":"Accessing a GPIO Pin with OpenJDK Device I/O","text":"A GPIO Pin can be accessed by referencing its index in the properties file, or by creating a Pin configuration object and feeding it to the DeviceManager as shown in the code examples below.
"},{"location":"java-application-development/how-to-use-gpio/#accessing-a-gpio-pin-by-its-index","title":"Accessing a GPIO Pin by its Index","text":"#Accessing the GPIO Pin number 17. The default behaviour is defined in the\n#jdk.dio.properties file\n#\n#i.e.:\n# gpio.GPIOPin = initValue:0, deviceNumber:0, direction:3, mode:-1, trigger:3\n# 17 = deviceType: gpio.GPIOPin, pinNumber:17, name:GPIO_USER_1\n\nGPIOPin led = (GPIOPin)DeviceManager.open(17);\n\nled.setValue(true) //Turns the LED on\nled.setValue(false) //Turns the LED off\nboolean status = led.getValue() //true if the LED is on\n
"},{"location":"java-application-development/how-to-use-gpio/#accessing-a-gpio-pin-using-a-device-configuration-object","title":"Accessing a GPIO Pin Using a Device Configuration Object","text":"#Accessing the Pin number 17 with custom configuration\n\nGPIOPinConfig pinConfig = new GPIOPinConfig(\n DeviceConfig.DEFAULT, //GPIO Controller number or name\n 17, //GPIO Pin number\n GPIOPinConfig.DIR_INPUT_ONLY, //Pin direction\n GPIOPinConfig.MODE_INPUT_PULL_DOWN, //Pin resistor\n GPIOPinConfig.TRIGGER_BOTH_EDGES, //Triggers\n false //initial value (for outputs)\n);\n\nGPIOPin button = (GPIOPin) DeviceManager.open(GPIOPin.class, pinConfig);\n\nbutton.setInputListener(new PinListener(){\n @Override\n public void valueChanged(PinEvent event) {\n System.out.println(\"PIN Status Changed!\");\n System.out.println(event.getLastTimeStamp() + \" - \" + event.getValue());\n }\n});\n
"},{"location":"java-application-development/how-to-use-legacy-bt-beacon-scanner/","title":"How to Use Legacy Bluetooth LE Beacon Scanner","text":"Warning
This guide uses the deprecated Kura Bluetooth APIs. Please consider to use the new ones.
"},{"location":"java-application-development/how-to-use-legacy-bt-beacon-scanner/#overview","title":"Overview","text":"The Bluetooth Beacon Scanner example is a bundle for Eclipse Kura that uses the Bluetooth LE service to search for near Beacon devices. A Beacon device is a Bluetooth Low Energy device that broadcasts its identity to nearby devices. It uses a specific BLE packet, called beacon or advertising packet, that contains the following information:
Proximity UUID - a 128-bit value that uniquely identifies one or more beacons as a certain type or from a certain organization.
Major value - an optional 16-bit unsigned integer that can group related beacons with the same proximity UUID.
Minor value - an optional 16-bit unsigned integer that differentiates beacons with the same proximity UUID and major value.
Tx Power - a value programmed into the beacon that enables distance from the beacon to be determined based on signal strength.
The Beacon Scanner bundle is configured with a Company Code in order to filter the near beacons. So, only beacons with a specific Company Code are discovered by the bundle and their information are reported. Moreover the bundle is able to roughly estimate the distance from the beacon.
For further information about the Beacons, please refer to the BLE Beacon Example.
"},{"location":"java-application-development/how-to-use-legacy-bt-beacon-scanner/#prerequisites","title":"Prerequisites","text":"Development Environment Setup
Hardware
Embedded device running Kura with Bluetooth 4.0 (LE) capabilities.
bluez_ packet must be installed on the embedded device. Follow the installation instructions in How to Use Bluetooth LE.
For this tutorial a Raspberry Pi Type B with a LMTechnologies LM506 Bluetooth 4.0 dongle is used.
"},{"location":"java-application-development/how-to-use-legacy-bt-beacon-scanner/#beacon-scanning-with-kura","title":"Beacon Scanning with Kura","text":"The Beacon Scanner bundle is a Kura example that allows you to configure the Company Code for the Beacon filtering and to start/stop the scanner procedure.
"},{"location":"java-application-development/how-to-use-legacy-bt-beacon-scanner/#develop-the-beacon-scanner-bundle","title":"Develop the Beacon Scanner Bundle","text":"The Beacon Scanner bundle code development follows the guidelines presented in the Hello World Application :
Create a Plug-in Project named org.eclipse.kura.example.beacon.scanner.
Create the class BeaconScannerExample.
Include the following bundles in the MANIFEST.MF:
The following files need to be implemented in order to write the source code:
META-INF/MANIFEST.MF - OSGI manifest that describes the bundle and its dependencies.
OSGI-INF/beaconExample.xml - declarative services definition that describes the services exposed and consumed by this bundle.
OSGI-INF/metatype/org.eclipse.kura.example.beacon.scanner.BeaconScannerExample.xml - configuration description of the bundle and its parameters, types, and defaults.
org.eclipse.kura.example.beacon.scanner.BeaconScannerExample.java - main implementation class.
The OSGI-INF/metatype/org.eclipse.kura.example.beacon.scanner.BeaconScannerExample.xml file describes the parameters for this bundle including the following:
enableScanning - enables Beacon scanning.
companyCode - defines a 16-bit company code as hex string.
iname - provides the name of bluetooth adapter.
The com.eurotech.example.beacon.scanner.BeaconScannerExample.java file contains the activate, deactivate and updated methods for this bundle. The activate and updated methods gets the properties from the configurable component and, if the scanning is enabled, call the setup private method. This method gets the BluetoothAdapter, enables the interface if needed, and starts the scan calling the bluetootAdapter.startBeaconScan(companyCode, listener) method. The arguments of the method are the companyCode and a listener that is notified when a device is detected. In this case the BeaconScannerExample class implements BluetoothBeaconScanListener. The following code sample shows the setup method:
private void setup() {\n\n this.publishTimes = new HashMap<String, Long>();\n\n this.bluetoothAdapter = this.bluetoothService.getBluetoothAdapter(this.adapterName);\n if (this.bluetoothAdapter != null) {\n this.bluetoothAdapter.startBeaconScan(this.companyCode, this);\n }\n\n}\n
Since BeaconScannerExample implements BluetoothBeaconScanListener, the onBeaconDataReceived method must be overridden. When a device is detected, the listener is notified and the onBeaconDataReceived method is called with a BluetoothBeaconData object. The BluetoothBeaconData class contains the following fields:
uuid - a 128-bit value that uniquely identifies one or more beacons as a certain type or from a certain organization.
address - the source of the beacon
major - an optional 16-bit unsigned integer that can group related beacons with the same proximity UUID.
minor - an optional 16-bit unsigned integer that differentiates beacons with the same proximity UUID and major value.
rssi - the Received Signal Strength Indication
txpower - a value programmed into the beacon that enables distance from the beacon to be determined based on signal strength.
The following code is an implementation of onBeaconDataReceived that logs the BluetoothBeaconData fields:
public void onBeaconDataReceived(BluetoothBeaconData beaconData) {\n\n logger.debug(\"Beacon from {} detected.\", beaconData.address);\n long now = System.nanoTime();\n\n Long lastPublishTime = this.publishTimes.get(beaconData.address);\n\n // If this beacon is new, or it last published more than 'rateLimit' ms ago\n if (lastPublishTime == null || (now - lastPublishTime) / 1000000L > this.rateLimit) {\n\n // Store the publish time against the address\n this.publishTimes.put(beaconData.address, now);\n if (this.cloudPublisher == null) {\n logger.info(\"No cloud publisher selected. Cannot publish!\");\n return;\n }\n\n // Publish the beacon data to the beacon's topic\n KuraPayload kp = new KuraPayload();\n kp.setTimestamp(new Date());\n kp.addMetric(\"uuid\", beaconData.uuid);\n kp.addMetric(\"txpower\", beaconData.txpower);\n kp.addMetric(\"rssi\", beaconData.rssi);\n kp.addMetric(\"major\", beaconData.major);\n kp.addMetric(\"minor\", beaconData.minor);\n kp.addMetric(\"distance\", calculateDistance(beaconData.rssi, beaconData.txpower));\n\n Map<String, Object> properties = new HashMap<String, Object>();\n properties.put(\"address\", beaconData.address);\n KuraMessage message = new KuraMessage(kp, properties);\n try {\n this.cloudPublisher.publish(message);\n } catch (KuraException e) {\n logger.error(\"Unable to publish\", e);\n }\n }\n}\n
Finally, the Beacon Scanner is able to roughly estimate the distance of the detected beacon using the calculateDistance method:
private double calculateDistance(int rssi, int txpower) {\n\n double distance;\n\n int ratioDB = txpower - rssi;\n double ratioLinear = Math.pow(10, (double) ratioDB / 10);\n distance = Math.sqrt(ratioLinear);\n\n return distance;\n}\n
"},{"location":"java-application-development/how-to-use-legacy-bt-beacon-scanner/#deploy-and-validate-the-bundle","title":"Deploy and Validate the Bundle","text":"In order to proceed, you need to know the IP address of your embedded gateway that is on the remote target unit. With this information, follow the mToolkit instructions for installing a single bundle to the remote target device located here. When the installation is complete, the bundle starts automatically.
In the Kura Gateway Administration Console, the BeaconScannerExample tab appears on the left and enables the device to be configured for scanning.
You should see a message similar to the one below from /var/log/kura.log indicating that the bundle was successfully installed and configured.
2016-08-08 14:39:48,351 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.s.BeaconScannerExample - Activating Bluetooth Beacon Scanner example...\n2016-08-08 14:39:48,353 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.s.BeaconScannerExample - Activating Bluetooth Beacon Scanner example...Done\n2016-08-08 14:39:48,373 [Component Resolve Thread (Bundle 6)] INFO o.e.k.c.c.ConfigurableComponentTracker - Adding ConfigurableComponent with pid org.eclipse.kura.example.beacon.scanner.BeaconScannerExample, service pid org.eclipse.kura.example.beacon.scanner.BeaconScannerExample and factory pid null\n2016-08-08 14:39:48,373 [Component Resolve Thread (Bundle 6)] INFO o.e.k.c.c.ConfigurationServiceImpl - Registration of ConfigurableComponent org.eclipse.kura.example.beacon.scanner.BeaconScannerExample by org.eclipse.kura.core.configuration.ConfigurationServiceImpl@1197c95...\n2016-08-08 14:40:40,186 [qtp23115489-40] WARN o.e.k.w.s.s.SkinServlet - Resource File /opt/eclipse/kura/console/skin/skin.js does not exist\n2016-08-08 14:40:56,996 [qtp23115489-42] INFO o.e.k.c.c.ConfigurationServiceImpl - Loading init configurations from: 1470667042563...\n2016-08-08 14:40:57,679 [qtp23115489-42] INFO o.e.k.c.c.ConfigurationServiceImpl - Merging configuration for pid: org.eclipse.kura.example.beacon.scanner.BeaconScannerExample\n2016-08-08 14:40:57,687 [qtp23115489-42] INFO o.e.k.c.c.ConfigurationServiceImpl - Updating Configuration of ConfigurableComponent org.eclipse.kura.example.beacon.scanner.BeaconScannerExample ... Done.\n2016-08-08 14:40:57,689 [qtp23115489-42] INFO o.e.k.c.c.ConfigurationServiceImpl - Writing snapshot - Saving /opt/eclipse/kura/data/snapshots/snapshot_1470667257688.xml...\n2016-08-08 14:40:57,914 [qtp23115489-42] INFO o.e.k.c.c.ConfigurationServiceImpl - Writing snapshot - Saving /opt/eclipse/kura/data/snapshots/snapshot_1470667257688.xml... Done.\n2016-08-08 14:40:57,916 [qtp23115489-42] INFO o.e.k.c.c.ConfigurationServiceImpl - Snapshots Garbage Collector. Deleting /opt/eclipse/kura/data/snapshots/snapshot_1470651681077.xml\n2016-08-08 14:40:58,013 [Component Resolve Thread (Bundle 6)] INFO o.e.k.l.b.l.BluetoothLeScanner - Starting bluetooth le beacon scan...\n
Using a device equipped with Kura acting as a Beacon (see BLE Beacon Example), the following lines appear on the log file when the device is detected:
2016-08-08 14:49:03,487 [BluetoothProcess BTSnoop Gobbler] INFO o.e.k.e.b.s.BeaconScannerExample - UUID : AAAAAAAABBBBCCCCDDDDEEEEEEEEEEEE\n2016-08-08 14:49:03,488 [BluetoothProcess BTSnoop Gobbler] INFO o.e.k.e.b.s.BeaconScannerExample - TxPower : -58\n2016-08-08 14:49:03,488 [BluetoothProcess BTSnoop Gobbler] INFO o.e.k.e.b.s.BeaconScannerExample - RSSI : -55\n2016-08-08 14:49:03,489 [BluetoothProcess BTSnoop Gobbler] INFO o.e.k.e.b.s.BeaconScannerExample - Major : 0\n2016-08-08 14:49:03,489 [BluetoothProcess BTSnoop Gobbler] INFO o.e.k.e.b.s.BeaconScannerExample - Minor : 0\n2016-08-08 14:49:03,490 [BluetoothProcess BTSnoop Gobbler] INFO o.e.k.e.b.s.BeaconScannerExample - Address : 5C:F3:70:60:63:8F\n2016-08-08 14:49:03,490 [BluetoothProcess BTSnoop Gobbler] INFO o.e.k.e.b.s.BeaconScannerExample - Distance : 0.7079457843841379\n
"},{"location":"java-application-development/how-to-use-legacy-bt-le-beacons/","title":"How to Use Legacy Bluetooth LE Beacons","text":"Warning
This guide uses the deprecated Kura Bluetooth APIs. Please consider to use the new ones.
"},{"location":"java-application-development/how-to-use-legacy-bt-le-beacons/#overview","title":"Overview","text":"The Bluetooth Beacon example is a simple bundle for Eclipse Kura that allows you to configure a device as a Beacon. A Beacon device is a Bluetooth Low Energy device that broadcasts its identity to nearby devices. It uses a specific BLE packet, called beacon or advertising packet, that contains the following information:
Proximity UUID - a 128-bit value that uniquely identifies one or more beacons as a certain type or from a certain organization.
Major value - an optional 16-bit unsigned integer that can group related beacons with the same proximity UUID.
Minor value - an optional 16-bit unsigned integer that differentiates beacons with the same proximity UUID and major value.
Tx Power - a value programmed into the beacon that enables distance from the beacon to be determined based on signal strength.
The advertising packet has a fixed format and is broadcasted periodically. The information contained in the advertising packet can be used by a receiver, typically a smartphone, to identify the beacon and to roughly estimate its distance.
"},{"location":"java-application-development/how-to-use-legacy-bt-le-beacons/#prerequisites","title":"Prerequisites","text":"Development Environment Setup
Hardware
Embedded device running Kura with Bluetooth 4.0 (LE) capabilities.
bluez_ packet must be installed on the embedded device. Follow the installation instructions in How to Use Bluetooth LE.
For this tutorial a Raspberry Pi Type B with a LMTechnologies LM506 Bluetooth 4.0 dongle is used.
"},{"location":"java-application-development/how-to-use-legacy-bt-le-beacons/#beacon-advertising-with-hcitool","title":"Beacon Advertising with hcitool","text":"After the embedded device is properly configured, the advertising may be started using the hcitool command contained in the bluez packet.
Plug in the Bluetooth dongle if needed and verify that the interface is up with the following command:
sudo hciconfig hci0\n
If the interface is down, enable it with the following command:
sudo hciconfig hci0 up\n
To configure the advertising packet, enter the following command:
sudo hcitool -i hci0 cmd 0x08 0x0008 1e 02 01 1a 1a ff 4c 00 02 15 aa aa aa aa bb bb cc cc dd dd ee ee ee ee ee ee 01 00 01 00 c5\n
In this example, the packet will contain the uuid aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee, major 1, minor 1 and Tx Power -59 dBm.
For further information about BLE commands and packet formats, refer to the Bluetooth 4.0 Core specifications
To set the advertising interval to 1 second, enter the following command:
sudo hcitool -i hci0 cmd 0x08 0x0006 a0 00 a0 00 03 00 00 00 00 00 00 00 00 07 00\n
Finally, to start the advertising, enter the following command:
sudo hcitool -i hci0 cmd 0x08 0x000a 01\n
To verify that the embedded device is broadcasting its beacon, use a smartphone with a iBeacon scanner app (e.g., iBeacon Finder, iBeacon Scanner, or iBeaconDetector on Android). To stop the advertising, write 0 to the register 0x000a as shown in the following command:
sudo hcitool -i hci0 cmd 0x08 0x000a 00\n
"},{"location":"java-application-development/how-to-use-legacy-bt-le-beacons/#beacon-advertising-with-kura","title":"Beacon Advertising with Kura","text":"The Beacon bundle is a simple example that allows you to configure the advertising packet, the time interval, and to start/stop the advertising.
"},{"location":"java-application-development/how-to-use-legacy-bt-le-beacons/#develop-the-beacon-bundle","title":"Develop the Beacon Bundle","text":"The Beacon bundle code development follows the guidelines presented in the Hello World Application :
Create a Plug-in Project named org.eclipse.kura.example.beacon.
Create the class BeaconExample.
Include the following bundles in the MANIFEST.MF:
The following files need to be implemented in order to write the source code:
META-INF/MANIFEST.MF - OSGI manifest that describes the bundle and its dependencies.
OSGI-INF/beaconExample.xml - declarative services definition that describes the services exposed and consumed by this bundle.
OSGI-INF/metatype/org.eclipse.kura.example.beacon.BeaconExample.xml - configuration description of the bundle and its parameters, types, and defaults.
org.eclipse.kura.example.beacon.BeaconExample.java - main implementation class.
The OSGI-INF/metatype/org.eclipse.kura.example.beacon.beaconExample.xml file describes the parameters for this bundle including the following:
enableAdvertising - enables Beacon advertising.
minBeaconInterval - sets the minimum time interval between beacons (milliseconds).
maxBeaconInterval - sets the maximum time interval between beacons (milliseconds).
uuid - defines a 128-bit uuid for beacon advertising expressed as hex string.
major - sets the major value.
minor - sets the minor value.
companyCode - defines a 16-bit company code as hex string.
txPower - indicates the transmission power measured at 1m away from the beacon expressed in dBm.
LELimited - defines the LE Discoverable Mode. Set false to advertise for 30.72s and then stops. Set true to advertise indefinitely.
BR_EDRSupported - indicates whether BR/EDR is supported.
LE_BRController - indicates whether LE and BR/EDR Controller operates simultaneously.
LE_BRHost - indicates whether LE and BR/EDR Host operates simultaneously.
iname - provides the name of bluetooth adapter.
The com.eurotech.example.beacon.BeaconExample.java file contains the activate and deactivate methods for this bundle. The activate method gets the BluetoothAdapter, enables the interface if needed, and executes the configureBeacon method that configures the device according to the properties. The following code sample shows part of the activate method:
// Get Bluetooth adapter with Beacon capabilities and ensure it is enabled\nthis.bluetoothAdapter = this.bluetoothService.getBluetoothAdapter(this.name, this);\nif (this.bluetoothAdapter != null) {\n logger.info(\"Bluetooth adapter interface => {}\", this.name);\n logger.info(\"Bluetooth adapter address => {}\", this.bluetoothAdapter.getAddress());\n logger.info(\"Bluetooth adapter le enabled => {}\", this.bluetoothAdapter.isLeReady());\n\n if (!this.bluetoothAdapter.isEnabled()) {\n logger.info(\"Enabling bluetooth adapter...\");\n this.bluetoothAdapter.enable();\n logger.info(\"Bluetooth adapter address => {}\", this.bluetoothAdapter.getAddress());\n }\n\n configureBeacon();\n\n} else {\n logger.warn(\"No Bluetooth adapter found ...\");\n}\n
The configureBeacon (shown below) is a private method:
private void configureBeacon() {\n\n if (this.enable) {\n\n if (this.minInterval != null && this.maxInterval != null) {\n this.bluetoothAdapter.setBeaconAdvertisingInterval(this.minInterval, this.maxInterval);\n }\n this.bluetoothAdapter.startBeaconAdvertising();\n if (this.uuid != null && this.major != null && this.minor != null && this.companyCode != null\n && this.txPower != null) {\n this.bluetoothAdapter.setBeaconAdvertisingData(this.uuid, this.major, this.minor, this.companyCode,\n this.txPower, this.leLimited, this.leLimited ? false : true, this.brSupported,\n this.brController, this.brHost);\n }\n } else {\n this.bluetoothAdapter.stopBeaconAdvertising();\n }\n}\n
"},{"location":"java-application-development/how-to-use-legacy-bt-le-beacons/#deploy-and-validate-the-bundle","title":"Deploy and Validate the Bundle","text":"In order to proceed, you need to know the IP address of your embedded gateway that is on the remote target unit. With this information, follow the mToolkit instructions for installing a single bundle to the remote target device located here. When the installation is complete, the bundle starts automatically.
In the Kura Gateway Administration Console, the BeaconExample tab appears on the left and enables the beacon to be configured for advertising.
You should see a message similar to the one below from /var/log/kura.log indicating that the bundle was successfully installed and configured.
2015-07-09 10:46:06,522 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.BeaconExample - Activating Bluetooth Beacon example...\n2015-07-09 10:46:06,639 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.BeaconExample - Bluetooth adapter interface => hci0\n2015-07-09 10:46:06,643 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.BeaconExample - Bluetooth adapter address => null\n2015-07-09 10:46:06,645 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.BeaconExample - Bluetooth adapter le enabled => false\n2015-07-09 10:46:06,664 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.BeaconExample - Enabling bluetooth adapter...\n2015-07-09 10:46:06,745 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.BeaconExample - Bluetooth adapter address => 5C:F3:70:60:63:9E\n2015-07-09 10:46:06,770 [Component Resolve Thread (Bundle 6)] INFO o.e.k.l.b.BluetoothAdapterImpl - Set Advertising Parameters on interface hci0\n2015-07-09 10:46:06,842 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.b.BluetoothBeaconListener - Command ogf 0x08, ocf 0x0006 Succeeded.\n2015-07-09 10:46:06,852 [Component Resolve Thread (Bundle 6)] INFO o.e.k.l.b.BluetoothAdapterImpl - Set Advertising Data on interface hci0\n2015-07-09 10:46:06,859 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.BeaconExample - Command results : 01 06 20 00\n2015-07-09 10:46:06,872 [Component Resolve Thread (Bundle 6)] INFO o.e.k.l.b.BluetoothAdapterImpl - Start Advertising on interface hci0\n2015-07-09 10:46:06,906 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.b.BluetoothBeaconListener - Command ogf 0x08, ocf 0x0008 Succeeded.\n2015-07-09 10:46:06,908 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.BeaconExample - Command results : 01 08 20 00\n2015-07-09 10:46:06,921 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.b.BluetoothBeaconListener - Command ogf 0x08, ocf 0x000a Succeeded.\n2015-07-09 10:46:06,923 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.BeaconExample - Command results : 01 0A 20 00\n2015-07-09 10:46:06,947 [Component Resolve Thread (Bundle 6)] INFO o.e.k.c.c.ConfigurableComponentTracker - Adding ConfigurableComponent org.eclipse.kura.example.beacon.BeaconExample\n2015-07-09 10:46:06,950 [Component Resolve Thread (Bundle 6)] INFO o.e.k.c.c.ConfigurationServiceImpl - Registration of ConfigurableComponent org.eclipse.kura.example.beacon.BeaconExample by org.eclipse.kura.core.configuration.ConfigurationServiceImpl@11120b6...\n2015-07-09 10:46:06,996 [Component Resolve Thread (Bundle 6)] INFO o.e.k.c.c.ConfigurationServiceImpl - Registering org.eclipse.kura.example.beacon.BeaconExample with ocd: org.eclipse.kura.core.configuration.metatype.Tocd@8af8b3 ...\n2015-07-09 10:46:06,999 [Component Resolve Thread (Bundle 6)] INFO o.e.k.c.c.ConfigurationServiceImpl - Registration Completed for Component org.eclipse.kura.example.beacon.BeaconExample.\n
Note that the bundle writes the string returned by the configuration commands to the log:
2015-07-09 10:46:06,859 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.BeaconExample - Command results : 01 06 20 00\n
The last number of the string is the error code. A value of \"00\" indicates a successful command. Refer to the Bluetooth 4.0 Core specifications for a complete list of the error codes.
Once the bundle is deployed, you can use a iBeacon scanner app to detect the bundle. Also, you can modify the bundle properties and verify the results in the scanner.
"},{"location":"java-application-development/how-to-use-legacy-bt-le/","title":"How to Use Legacy Bluetooth LE","text":"Warning
This guide uses the deprecated Kura Bluetooth APIs. Please consider to use the new ones.
"},{"location":"java-application-development/how-to-use-legacy-bt-le/#overview","title":"Overview","text":"This section provides an example of how to develop a simple bundle that discovers and connects to a Smart device (BLE), retrieves data from it, and publishes the results to the cloud. This example uses the TI SensorTag based on CC2541 or CC2650. For more information about this device, refer to https://www.ti.com/tool/cc2541dk-sensor and https://www.ti.com/tool/TIDC-CC2650STK-SENSORTAG.
You will learn how to perform the following functions:
Prepare the embedded device to communicate with a Smart device
Develop a bundle retrieves data from the device
Optionally publish the data in the cloud
Setting up Kura Development Environment
Hardware
Use an embedded device running Kura with Bluetooth 4.0 (LE) capabilities
This tutorial uses a Raspberry Pi Type B with a LMTechnologies LM506 Bluetooth 4.0 dongle.
"},{"location":"java-application-development/how-to-use-legacy-bt-le/#prepare-the-embedded-device","title":"Prepare the Embedded Device","text":"In order to communicate with Smart devices, the bluez package must be installed on the embedded device. To do so, make sure you have the necessary libraries on the Raspberry Pi and proceed as follows:
sudo apt-get install libusb-dev libdbus-1-dev libglib2.0-dev libudev-dev libical-dev libreadline-dev\n
Next, download and uncompress the package:
sudo wget https://www.kernel.org/pub/linux/bluetooth/bluez-4.101.tar.xz\nsudo tar xvf bluez-4.101.tar\n
Change to the blues folder, and then configure and install the package:
cd bluez-4.101\nsudo ./configure --disable-systemd --enable-tools\nsudo make\nsudo make install\n
Finally, change the location of the hciconfig and gatttool commands:
sudo mv /usr/local/sbin/hciconfig /usr/sbin\nsudo mv /usr/local/bin/gatttool /usr/sbin\n
Info
Both bluez 4.101 and 5.XX are supported.
"},{"location":"java-application-development/how-to-use-legacy-bt-le/#sensortag-communication-via-command-line","title":"SensorTag Communication via Command Line","text":"Once configured, you can scan and connect with a Smart device. A TI SensorTag is used in the example that follows.
Plug in the Bluetooth dongle if needed and verify that the interface is up:
sudo hciconfig hci0\n
If the interface is down, enable it with the following command:
sudo hciconfig hci0 up\n
Perform a BLE scan with hcitool (this process may be interrupted with ctrl-c):
sudo hcitool lescan\nLE Scan ...\nBC:6A:29:AE:CC:96 (unknown)\nBC:6A:29:AE:CC:96 SensorTag\n
If the SensorTag is not listed, press the button on the left side of the device to make it discoverable. Interactive communication with the device is possible using the gatttool:
sudo gatttool -b BC:6A:29:AE:CC:96 -I\n[ ][BC:6A:29:AE:CC:96][LE]> connect\n[CON][BC:6A:29:AE:CC:96][LE]>\n
If the output of the connect command is
connect: Connection refused (111)\n
then you have to enable LE capabilities on your BT interface: cd bluez-4.101/mgmt\nsudo ./btmgmt le on\n
In order to read the sensor values from the SensorTag, you need to write some registers on the device. The example that follows shows the procedure for retrieving the temperature value from the SensorTag based on the CC2541.
Once connected with gatttool, the IR temperature sensor is enabled to write the value 01 to the handle 0x0029:
[CON][BC:6A:29:AE:CC:96][LE]> char-write-cmd 0x0029 01\n
Next, the temperature value is read from the 0x0025 handle:
[CON][BC:6A:29:AE:CC:96][LE]> char-read-hnd 0x0025\n[CON][BC:6A:29:AE:CC:96][LE]>\nCharacteristic value/descriptor: a7 fe 2c 0d\",\n
In accordance with the documentation, the retrieved raw values have to be refined in order to obtain the ambient and object temperature.
Enable notifications writing the value 0001 to the 0x0026 register:
[CON][BC:6A:29:AE:CC:96][LE]> char-write-cmd 0x0026 0100\n[CON][BC:6A:29:AE:CC:96][LE]>\nNotification handle = 0x0025 value: a5 fe 3c 0d\n[CON][BC:6A:29:AE:CC:96][LE]>\nNotification handle = 0x0025 value: 9f fe 3c 0d\n[CON][BC:6A:29:AE:CC:96][LE]>\nNotification handle = 0x0025 value: 9a fe 3c 0d\n
Stop the notifications by writing 0000 to the same register:
[CON][BC:6A:29:AE:CC:96][LE]>\nNotification handle = 0x0025 value: 9e fe 3c 0d\n[CON][BC:6A:29:AE:CC:96][LE]> char-write-cmd 0x0026 0000\nNotification handle = 0x0025 value: a3 fe 3c 0d\n[CON][BC:6A:29:AE:CC:96][LE]>\n
Info
bluez 5.XX comes with the bluetoothctl tool that can be used in place of hcitool and gatttool. Please refer to the man page and help for more details.
"},{"location":"java-application-development/how-to-use-legacy-bt-le/#ble-bundle-for-ti-sensortag","title":"BLE Bundle for TI SensorTag","text":"The BLE bundle performs the following operations:
Starts a scan for smart devices (lescan)
Selects all the TI SensorTag in range
Connects to the discovered SensorTags and discovers their capabilities
Reads data from all the sensors onboard and writes the values in the log file
Warning
The Legacy Bluetooth LE Example supports TI SensorTag CC2541 (all firmware versions) and CC2650 (firmware version above 1.20)
"},{"location":"java-application-development/how-to-use-legacy-bt-le/#develop-the-ble-bundle","title":"Develop the BLE Bundle","text":"Once the required packages are installed and communication with the SensorTag via command line is established, you may start to develop the BLE bundle. For more detailed information about bundle development (i.e., the plug-in project, classes, and MANIFEST file configuration), please refer to the Hello World Application.
Create a Plug-in Project named org.eclipse.kura.example.ble.tisensortag.
Create the following classes: BluetoothLe, TiSensorTag, and TiSensorTagGatt.
Include the following bundles in the MANIFEST.MF:
The following files need to be implemented in order to write the source code:
META-INF/MANIFEST.MF - OSGI manifest that describes the bundle and its dependencies.
OSGI-INF/bleExample.xml - declarative services definition that describes the services exposed and consumed by this bundle.
OSGI-INF/metatype/org.eclipse.kura.example.ble.tisensortag.BluetoothLe.xml - configuration description of the bundle and its parameters, types, and defaults.
org.eclipse.kura.example.ble.tisensortag.BluetoothLe.java - main implementation class.
org.eclipse.kura.example.ble.tisensortag.TiSensorTag.java - class used to connect with a TI SensorTag.
org.eclipse.kura.example.ble.tisensortag.TiSensorTagGatt.java - class that describes all the handles and UUIDs to access to the SensorTag sensors.
The OSGI-INF/metatype/org.eclipse.kura.example.ble.tisensortag.BluetoothLe.xml file describes the parameters for this bundle including the following:
scan_time - specifies the length of time to scan for devices in seconds.
period - specifies the time interval in seconds between two publishes.
enableTermometer - Enable temperature sensor.
enableAccelerometer - Enable accelerometer sensor.
...
publishTopic - supplies the topic to publish data to the cloud.
iname - Name of bluetooth adapter.
The org.eclipse.kura.example.ble.tisensortag.BluetoothLe.java file contains the activate, deactivate and updated methods for this bundle. The activate and update methods gets the BluetoothAdapter and schedules the execution of the performScan method every second and readTiSensorTags every user defined period. The following code sample shows part of the code:
this.options = new BluetoothLeOptions(properties);\nthis.startTime = 0;\nif (this.options.isEnableScan()) {\n // re-create the worker\n this.worker = Executors.newScheduledThreadPool(2);\n\n // Get Bluetooth adapter and ensure it is enabled\n this.bluetoothAdapter = this.bluetoothService.getBluetoothAdapter(this.options.getIname());\n if (this.bluetoothAdapter != null) {\n logger.info(\"Bluetooth adapter interface => {}\", this.options.getIname());\n if (!this.bluetoothAdapter.isEnabled()) {\n logger.info(\"Enabling bluetooth adapter...\");\n this.bluetoothAdapter.enable();\n }\n logger.info(\"Bluetooth adapter address => {}\", this.bluetoothAdapter.getAddress());\n\n this.scanHandle = this.worker.scheduleAtFixedRate(this::performScan, 0, 1, TimeUnit.SECONDS);\n this.readHandle = this.worker.scheduleAtFixedRate(this::readTiSensorTags, 0, this.options.getPeriod(),\n TimeUnit.SECONDS);\n } else {\n logger.info(\"Bluetooth adapter {} not found.\", this.options.getIname());\n }\n}\n
The performScan method manages the start and stop of the scanning procedure as shown below.
void performScan() {\n\n // Scan for devices\n if (this.bluetoothAdapter.isScanning()) {\n logger.info(\"bluetoothAdapter.isScanning\");\n if (System.currentTimeMillis() - this.startTime >= this.options.getScantime() * 1000) {\n this.bluetoothAdapter.killLeScan();\n }\n } else {\n if (System.currentTimeMillis() - this.startTime >= this.options.getPeriod() * 1000) {\n logger.info(\"startLeScan\");\n this.bluetoothAdapter.startLeScan(this);\n this.startTime = System.currentTimeMillis();\n }\n }\n\n}\n
The BluetoothLe class implements the org.eclipse.kura.bluetooth.BluetoothLeScanListener interface and the onScanResults method is called when the scan procedure ends. The method filters the scan results and stores the SensorTag devices in a list. Part of the onScanResults method is shown below.
@Override\n public void onScanResults(List<BluetoothDevice> scanResults) {\n\n // Scan for TI SensorTag\n for (BluetoothDevice bluetoothDevice : scanResults) {\n logger.info(\"Address {} Name {}\", bluetoothDevice.getAdress(), bluetoothDevice.getName());\n\n if (bluetoothDevice.getName().contains(\"SensorTag\") && !isSensorTagInList(bluetoothDevice.getAdress())) {\n this.tiSensorTagList.add(new TiSensorTag(bluetoothDevice));\n }\n }\n\n }\n
The readTiSensorTags is responsible to read the sensors for all the SensorTags contained in the list and publish the resulting data.
private void readTiSensorTags() {\n // connect to TiSensorTags\n this.tiSensorTagList.forEach(myTiSensorTag -> {\n connect(myTiSensorTag);\n\n if (myTiSensorTag.isConnected()) {\n ...\n\n KuraPayload payload = new KuraPayload();\n payload.setTimestamp(new Date());\n payload.addMetric(\"Firmware\", myTiSensorTag.getFirmwareRevision());\n if (myTiSensorTag.isCC2650()) {\n payload.addMetric(\"Type\", \"CC2650\");\n } else {\n payload.addMetric(\"Type\", \"CC2541\");\n }\n readServicesAndCharacteristics(myTiSensorTag);\n readSensors(myTiSensorTag, payload);\n myTiSensorTag.enableIOService();\n\n publishData(myTiSensorTag, payload);\n\n ...\n } else {\n logger.warn(\"Cannot connect to TI SensorTag {}.\", myTiSensorTag.getBluetoothDevice().getAdress());\n }\n });\n\n}\n
Since it is not possible to poll the status of the buttons on the SensorTag, the BLE example enables the notifications for them.
"},{"location":"java-application-development/how-to-use-legacy-bt-le/#orgeclipsekuraexampleblesensortagtisensortagjava-file","title":"org.eclipse.kura.example.ble.sensortag.TiSensorTag.java File","text":"The org.eclipse.kura.example.ble.sensortag.TiSensorTag class is used to connect and disconnect to the SensorTag. It also contains the methods to configure and read data from the sensor. The connection method uses the BluetoothGatt Service as shown below:
public boolean connect(String adapterName) {\n this.bluetoothGatt = this.device.getBluetoothGatt();\n boolean connected = false;\n try {\n connected = this.bluetoothGatt.connect(adapterName);\n } catch (KuraException e) {\n logger.error(e.toString());\n }\n if (connected) {\n this.bluetoothGatt.setBluetoothLeNotificationListener(this);\n setFirmwareRevision();\n this.isConnected = true;\n return true;\n } else {\n // If connect command is not executed, close gatttool\n this.bluetoothGatt.disconnect();\n this.isConnected = false;\n return false;\n }\n}\n
A set of methods for reading from and writing to the internal register of the device are included in the class. The following code sample presents the methods to manage the temperature sensor.
/*\n* Enable temperature sensor\n*/\npublic void enableThermometer() {\n // Write \"01\" to enable thermometer sensor\n if (this.cc2650) {\n this.bluetoothGatt.writeCharacteristicValue(TiSensorTagGatt.HANDLE_TEMP_SENSOR_ENABLE_2650, \"01\");\n } else {\n this.bluetoothGatt.writeCharacteristicValue(TiSensorTagGatt.HANDLE_TEMP_SENSOR_ENABLE_2541, \"01\");\n }\n}\n\n/*\n* Disable temperature sensor\n*/\npublic void disableThermometer() {\n // Write \"00\" disable thermometer sensor\n if (this.cc2650) {\n this.bluetoothGatt.writeCharacteristicValue(TiSensorTagGatt.HANDLE_TEMP_SENSOR_ENABLE_2650, \"00\");\n } else {\n this.bluetoothGatt.writeCharacteristicValue(TiSensorTagGatt.HANDLE_TEMP_SENSOR_ENABLE_2541, \"00\");\n }\n}\n\n/*\n* Read temperature sensor\n*/\npublic double[] readTemperature() {\n double[] temperatures = new double[2];\n // Read value\n try {\n if (this.cc2650) {\n temperatures = calculateTemperature(\n this.bluetoothGatt.readCharacteristicValue(TiSensorTagGatt.HANDLE_TEMP_SENSOR_VALUE_2650));\n } else {\n temperatures = calculateTemperature(\n this.bluetoothGatt.readCharacteristicValue(TiSensorTagGatt.HANDLE_TEMP_SENSOR_VALUE_2541));\n }\n } catch (KuraException e) {\n logger.error(e.toString());\n }\n return temperatures;\n}\n\n/*\n* Read temperature sensor by UUID\n*/\npublic double[] readTemperatureByUuid() {\n double[] temperatures = new double[2];\n try {\n temperatures = calculateTemperature(\n this.bluetoothGatt.readCharacteristicValueByUuid(TiSensorTagGatt.UUID_TEMP_SENSOR_VALUE));\n } catch (KuraException e) {\n logger.error(e.toString());\n }\n return temperatures;\n}\n\n/*\n* Enable temperature notifications\n*/\npublic void enableTemperatureNotifications(TiSensorTagNotificationListener listener) {\n setListener(listener);\n // Write \"01:00 to enable notifications\n if (this.cc2650) {\n this.bluetoothGatt.writeCharacteristicValue(TiSensorTagGatt.HANDLE_TEMP_SENSOR_NOTIFICATION_2650,\n ENABLE_NOTIFICATIONS);\n } else {\n this.bluetoothGatt.writeCharacteristicValue(TiSensorTagGatt.HANDLE_TEMP_SENSOR_NOTIFICATION_2541,\n ENABLE_NOTIFICATIONS);\n }\n}\n\n/*\n* Disable temperature notifications\n*/\npublic void disableTemperatureNotifications() {\n unsetListener();\n // Write \"00:00 to enable notifications\n if (this.cc2650) {\n this.bluetoothGatt.writeCharacteristicValue(TiSensorTagGatt.HANDLE_TEMP_SENSOR_NOTIFICATION_2650,\n DISABLE_NOTIFICATIONS);\n } else {\n this.bluetoothGatt.writeCharacteristicValue(TiSensorTagGatt.HANDLE_TEMP_SENSOR_NOTIFICATION_2541,\n DISABLE_NOTIFICATIONS);\n }\n}\n\n/*\n * Set sampling period (only for CC2650)\n */\npublic void setThermometerPeriod(String period) {\n this.bluetoothGatt.writeCharacteristicValue(TiSensorTagGatt.HANDLE_TEMP_SENSOR_PERIOD_2650, period);\n}\n\n/*\n* Calculate temperature\n*/\nprivate double[] calculateTemperature(String value) {\n\n logger.info(\"Received temperature value: {}\", value);\n\n double[] temperatures = new double[2];\n\n byte[] valueByte = hexStringToByteArray(value.replace(\" \", \"\"));\n\n if (this.cc2650) {\n int ambT = shortUnsignedAtOffset(valueByte, 2);\n int objT = shortUnsignedAtOffset(valueByte, 0);\n temperatures[0] = (ambT >> 2) * 0.03125;\n temperatures[1] = (objT >> 2) * 0.03125;\n } else {\n\n int ambT = shortUnsignedAtOffset(valueByte, 2);\n int objT = shortSignedAtOffset(valueByte, 0);\n temperatures[0] = ambT / 128.0;\n\n double vobj2 = objT;\n vobj2 *= 0.00000015625;\n\n double tdie = ambT / 128.0 + 273.15;\n\n double s0 = 5.593E-14; // Calibration factor\n double a1 = 1.75E-3;\n double a2 = -1.678E-5;\n double b0 = -2.94E-5;\n double b1 = -5.7E-7;\n double b2 = 4.63E-9;\n double c2 = 13.4;\n double tref = 298.15;\n double s = s0 * (1 + a1 * (tdie - tref) + a2 * Math.pow(tdie - tref, 2));\n double vos = b0 + b1 * (tdie - tref) + b2 * Math.pow(tdie - tref, 2);\n double fObj = vobj2 - vos + c2 * Math.pow(vobj2 - vos, 2);\n double tObj = Math.pow(Math.pow(tdie, 4) + fObj / s, .25);\n\n temperatures[1] = tObj - 273.15;\n }\n\n return temperatures;\n}\n
The TiSensorTag class implements the org.eclipse.kura.bluetooth.BluetoothLeNotificationListener interface and the method onDataReceived is called when a BLE notification is received. In this example the notifications are used only for the buttons. The method is shown below.
public void onDataReceived(String handle, String value) {\n\n if (this.notificationListener != null) {\n Map<String, Object> values = new HashMap<>();\n if (handle.equals(TiSensorTagGatt.HANDLE_KEYS_STATUS_2541)\n || handle.equals(TiSensorTagGatt.HANDLE_KEYS_STATUS_2650)) {\n logger.info(\"Received keys value: {}\", value);\n if (!value.equals(\"00\")) {\n values.put(\"Keys\", Integer.parseInt(value));\n this.notificationListener.notify(this.device.getAdress(), values);\n }\n } else if (handle.equals(TiSensorTagGatt.HANDLE_TEMP_SENSOR_VALUE_2541)\n || handle.equals(TiSensorTagGatt.HANDLE_TEMP_SENSOR_VALUE_2650)) {\n double[] temperatures = calculateTemperature(value);\n values.put(\"Ambient\", temperatures[0]);\n values.put(\"Target\", temperatures[1]);\n this.notificationListener.notify(this.device.getAdress(), values);\n }\n }\n\n}\n
"},{"location":"java-application-development/how-to-use-legacy-bt-le/#deploy-and-validate-the-bundle","title":"Deploy and Validate the Bundle","text":"In order to proceed, you need to know the IP address of your embedded gateway that is on the remote target unit. Once you do, follow the mToolkit instructions for installing a single bundle to the remote target device located here. When the installation completes, the bundle starts automatically. You should see a message similar to the one below from /var/log/kura.log indicating that the bundle was successfully installed and configured, and started to search for TI SensorTags.
2015-11-11 13:38:19,208 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.t.BluetoothLe - Activating BluetoothLe example...\n2015-11-11 13:38:19,382 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.t.BluetoothLe - Bluetooth adapter interface => hci0\n2015-11-11 13:38:19,383 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.t.BluetoothLe - Bluetooth adapter address => 5C:F3:70:60:63:8F\n2015-11-11 13:38:19,383 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.t.BluetoothLe - Bluetooth adapter le enabled => true\n2015-11-11 13:38:19,395 [pool-26-thread-1] INFO o.e.k.e.b.t.BluetoothLe - startLeScan\n2015-11-11 13:38:19,396 [pool-26-thread-1] INFO o.e.k.l.b.l.BluetoothLeScanner - Starting bluetooth le scan...\n2015-11-11 13:38:19,406 [Component Resolve Thread (Bundle 6)] INFO o.e.k.c.c.ConfigurableComponentTracker - Adding ConfigurableComponent org.eclipse.kura.example.ble.tisensortag.BluetoothLe\n2015-11-11 13:38:19,408 [Component Resolve Thread (Bundle 6)] INFO o.e.k.c.c.ConfigurationServiceImpl - Registration of ConfigurableComponent org.eclipse.kura.example.ble.tisensortag.BluetoothLe by org.eclipse.kura.core.configuration.ConfigurationServiceImpl@19cb019...\n2015-11-11 13:38:19,424 [Component Resolve Thread (Bundle 6)] INFO o.e.k.c.c.ConfigurationServiceImpl - Registering org.eclipse.kura.example.ble.tisensortag.BluetoothLe with ocd: org.eclipse.kura.core.configuration.metatype.Tocd@106b1d9 ...\n2015-11-11 13:38:19,426 [Component Resolve Thread (Bundle 6)] INFO o.e.k.c.c.ConfigurationServiceImpl - Registration Completed for Component org.eclipse.kura.example.ble.tisensortag.BluetoothLe.\n2015-11-11 13:38:20,394 [pool-26-thread-1] INFO o.e.k.e.b.t.BluetoothLe - m_bluetoothAdapter.isScanning\n2015-11-11 13:38:21,394 [pool-26-thread-1] INFO o.e.k.e.b.t.BluetoothLe - m_bluetoothAdapter.isScanning\n2015-11-11 13:38:22,394 [pool-26-thread-1] INFO o.e.k.e.b.t.BluetoothLe - m_bluetoothAdapter.isScanning\n2015-11-11 13:38:23,394 [pool-26-thread-1] INFO o.e.k.e.b.t.BluetoothLe - m_bluetoothAdapter.isScanning\n2015-11-11 13:38:24,394 [pool-26-thread-1] INFO o.e.k.e.b.t.BluetoothLe - m_bluetoothAdapter.isScanning\n2015-11-11 13:38:25,394 [pool-26-thread-1] INFO o.e.k.e.b.t.BluetoothLe - m_bluetoothAdapter.isScanning\n2015-11-11 13:38:25,396 [pool-26-thread-1] INFO o.e.k.l.b.l.BluetoothLeScanner - Killing hcitool...\n2015-11-11 13:38:25,449 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - LE Scan ...\n2015-11-11 13:38:25,450 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - 7F:D8:F8:45:6B:C2 (unknown)\n2015-11-11 13:38:25,452 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - 7F:D8:F8:45:6B:C2 (unknown)\n2015-11-11 13:38:25,453 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - BC:6A:29:AE:CC:96 (unknown)\n2015-11-11 13:38:25,454 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - BC:6A:29:AE:CC:96 SensorTag\n2015-11-11 13:38:25,455 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - 68:64:4B:3F:04:9B (unknown)\n2015-11-11 13:38:25,456 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - 68:64:4B:3F:04:9B (unknown)\n2015-11-11 13:38:25,457 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - 18:EE:69:15:21:B0 (unknown)\n2015-11-11 13:38:25,458 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - 18:EE:69:15:21:B0 (unknown)\n2015-11-11 13:38:25,459 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - m_scanResult.add 68:64:4B:3F:04:9B - (unknown)\n2015-11-11 13:38:25,464 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - m_scanResult.add 18:EE:69:15:21:B0 - (unknown)\n2015-11-11 13:38:25,465 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - m_scanResult.add BC:6A:29:AE:CC:96 - SensorTag\n2015-11-11 13:38:25,466 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - m_scanResult.add 7F:D8:F8:45:6B:C2 - (unknown)\n2015-11-11 13:38:25,467 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Address 68:64:4B:3F:04:9B Name (unknown)\n2015-11-11 13:38:25,467 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Found device = 68:64:4B:3F:04:9B\n2015-11-11 13:38:25,468 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Address 18:EE:69:15:21:B0 Name (unknown)\n2015-11-11 13:38:25,468 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Found device = 18:EE:69:15:21:B0\n2015-11-11 13:38:25,469 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Address BC:6A:29:AE:CC:96 Name SensorTag\n2015-11-11 13:38:25,469 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - TI SensorTag BC:6A:29:AE:CC:96 found.\n2015-11-11 13:38:25,470 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Address 7F:D8:F8:45:6B:C2 Name (unknown)\n2015-11-11 13:38:25,470 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Found device = 7F:D8:F8:45:6B:C2\n2015-11-11 13:38:25,470 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Connecting to TiSensorTag...\n2015-11-11 13:38:25,475 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothGattImpl - Sending connect message...\n2015-11-11 13:38:25,859 [DnsMonitorServiceImpl] WARN o.e.k.n.a.m.DnsMonitorServiceImpl - Not Setting DNS servers to empty\n2015-11-11 13:38:26,883 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.TiSensorTag - Received temperature value: 7f fe fc 0c\n2015-11-11 13:38:26,885 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Ambient: 25.96875 Target: 20.801530505264225\n2015-11-11 13:38:28,028 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.TiSensorTag - Received accelerometer value: ff 06 42\n2015-11-11 13:38:28,029 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Acc X: -0.015625 Acc Y: 0.09375 Acc Z: -1.03125\n2015-11-11 13:38:29,182 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.TiSensorTag - Received barometer value: e8 6a 22 56\n2015-11-11 13:38:29,183 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Humidity: 36.053864\n2015-11-11 13:38:30,327 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.TiSensorTag - Received magnetometer value: e5 f6 d6 fc 62 04\n2015-11-11 13:38:30,328 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Mag X: 203.43018 Mag Y: 320.43457 Mag Z: 765.7471\n2015-11-11 13:38:32,623 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.TiSensorTag - Received pressure value: 1d fd dd 99\n2015-11-11 13:38:32,625 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Pre : 99334.60900594086\n2015-11-11 13:38:33,767 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.TiSensorTag - Received gyro value: cc 01 1d ff d2 ff\n2015-11-11 13:38:33,769 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Gyro X: -101.55487 Gyro Y: -58.58612 Gyro Z: -87.898254\n2015-11-11 13:38:33,769 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.TiSensorTag - Not optical sensor on CC2541.\n2015-11-11 13:38:34,770 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.TiSensorTag - Not optical sensor on CC2541.\n2015-11-11 13:38:34,771 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Light: 0.0\n
"},{"location":"java-application-development/how-to-use-modbus/","title":"How to Use Modbus","text":"ModbusProtocolDevice is a service that provides a connection to a device or a network of devices over Serial Line (RS-232/RS-485) or Ethernet using the Modbus protocol. This service implements a subset of the Modbus Application Protocol as defined by Modbus Organization (for more information, refer to http://www.modbus.org/specs.php).
The ModbusProtocolDevice service needs to receive a valid Modbus configuration including the following parameters:
Modbus protocol mode - defines the protocol mode as RTU or ASCII (only RTU mode for Ethernet connections).
Timeout - sets the timeout in order to detect a disconnected device.
The ModbusProtocolDevice service also requires a valid Serial Line or Ethernet connection configuration including the following parameters:
parity
Ethernet
When a valid configuration is received, the ModbusProtocolDevice service tries to open the communication port. Serial Line communication uses the CommConnection class; Ethernet communication is based on java.net.Socket. When the communication is established, the client makes direct calls to the Modbus functions. The first parameter of each method is the Modbus address of the queried unit. This address must be in the range of 1 - 247.
"},{"location":"java-application-development/how-to-use-modbus/#function-codes","title":"Function Codes","text":"The following function codes are implemented within the ModbusProtocolDevice service:
01 (0x01) readCoils(int unitAddr,\u00a0 int dataAddress, int count) - read 1 to 2000 maximum contiguous status of coils from the attached field device with address \"unitAddr\". An array of booleans representing the requested data points is returned.
02 (0x02) readDiscreteInputs(int unitAddr,\u00a0 int dataAddress, int count) - read 1 to 2000 maximum contiguous status of discrete inputs from the attached field device with address \"unitAddr\". An array of booleans representing the requested data points is returned.
03 (0x03) readHoldingRegisters(int unitAddr,\u00a0 int dataAddress, int count) - read contents of 1 to 125 maximum contiguous block of holding registers from the attached field device with address \"unitAddr\". An array of int representing the requested data points (data registers on 2 bytes) is returned.
04 (0x04) readInputRegisters(int unitAddr,\u00a0 int dataAddress, int count) - read contents of 1 to 125 maximum contiguous block of input registers from the attached field device with address \"unitAddr\". An array of int representing the requested data points (data registers on 2 bytes) is returned.
05 (0x05) writeSingleCoil(int unitAddr,\u00a0 int dataAddress, boolean data) - write a single output to either ON or OFF in the attached field device with address \"unitAddr\".
06 (0x06) writeSingleRegister(int unitAddr,\u00a0 int dataAddress, int data) - write a single holding register in the attached field device with address \"unitAddr\".
15 (0x0F) writeMultipleCoils(int unitAddr,\u00a0 int dataAddress, boolean[ ] data) - write multiple coils in a sequence of coils to either ON or OFF in the attached field device with address \"unitAddr\".
16 (0x10) writeMultipleRegister(int unitAddr,\u00a0 int dataAddress, int[ ] data) - write a block of contiguous registers (1 to 123) in the attached field device with address \"unitAddr\".
All functions throw a ModbusProtocolException. Valid exceptions include:
INVALID_CONFIGURATION
NOT_AVAILABLE
NOT_CONNECTED
TRANSACTION_FAILURE
The ModbusProtocolDeviceService is an OSGi declarative service referenced in the client XML definition file:
<reference bind=\"setModbusProtocolDeviceService\"\n cardinality=\"1..1\"\n interface=\"org.eclipse.kura.protocol.modbus.ModbusProtocolDeviceService\"\n name=\"ModbusProtocolDeviceService\"\n policy=\"static\"\n unbind=\"unsetModbusProtocolDeviceService\"/>\n
public void setModbusProtocolDeviceService(ModbusProtocolDeviceService modbusService) {\n this.m_protocolDevice = modbusService;\n}\n\npublic void unsetModbusProtocolDeviceService(ModbusProtocolDeviceService modbusService) {\n this.m_protocolDevice = null;\n}\n
if(m_protocolDevice!=null){\n m_protocolDevice.disconnect();\n m_protocolDevice.configureConnection(modbusSerialProperties);\n}\n
If no exception occurs, the ModbusProtocolDevice can then be used to exchange data: boolean[] digitalInputs = m_protocolDevice.readDiscreteInputs(1, 2048, 8);\nint[] analogInputs = m_protocolDevice.readInputRegisters(1, 512, 8);\nboolean[] digitalOutputs = m_protocolDevice.readCoils(1, 2048, 6); // LEDS\n\n// to set LEDS\nm_protocolDevice.writeSingleCoil(1, 2047 + LED, On?TurnON:TurnOFF);\n
"},{"location":"java-application-development/how-to-use-new-beacon-apis/","title":"How to Use New Beacon APIs","text":""},{"location":"java-application-development/how-to-use-new-beacon-apis/#overview","title":"Overview","text":"Starting from version 3.1.0, Eclipse Kura implements a new set of APIs for managing Bluetooth Low Energy and Beacon devices. The new APIs replace the existing Bluetooth APIs, but the old ones are still available and can be used. So, the applications developed before Kura 3.1.0 continue to work.
The purpose of the new BLE Beacon APIs is to simplify the development of applications that interact with Bluetooth LE Beacon devices, offering clear and easy-to-use methods for advertising and scanning. Eclipse Kura offers out-of-the-box the implementation of the Beacon APIs for iBeacon\u2122 and Eddystone\u2122 technologies. Moreover, the new APIs allow to easily integrate new beacon implementations with Eclipse Kura.
"},{"location":"java-application-development/how-to-use-new-beacon-apis/#how-to-use-kura-ibeacontm-apis","title":"How to use Kura iBeacon\u2122 APIs","text":"This section briefly presents how to use the iBeacon\u2122 implementation of the Kura Beacon APIs, providing several code snippets to explain how to perform common operations on iBeacons. For a complete example on iBeacon advertising and scanning, please refer to the new iBeacon\u2122 advertiser and iBeacon\u2122 scanner examples. For more information about iBeacon\u2122 please refer to official page.
An application that wants to use the iBeacon\u2122 implementation of Kura Beacon APIs should bind the BluetoothLeService and BluetoothLeIBeaconService OSGI services, as shown in the following Java snippet:
public void setBluetoothLeService(BluetoothLeService bluetoothLeService) {\n this.bluetoothLeService = bluetoothLeService;\n}\n\npublic void unsetBluetoothLeService(BluetoothLeService bluetoothLeService) {\n this.bluetoothLeService = null;\n}\n\npublic void setBluetoothLeIBeaconService(BluetoothLeIBeaconService bluetoothLeIBeaconService) {\n this.bluetoothLeIBeaconService = bluetoothLeIBeaconService;\n}\n\npublic void unsetBluetoothLeIBeaconService(BluetoothLeIBeaconService bluetoothLeIBeaconService) {\n this.bluetoothLeIBeaconService = null;\n}\n
and in the component definition:
<reference bind=\"setBluetoothLeService\" \n cardinality=\"1..1\" \n interface=\"org.eclipse.kura.bluetooth.le.BluetoothLeService\" \n name=\"BluetoothLeService\" \n policy=\"static\" \n unbind=\"unsetBluetoothLeService\"/>\n\n<reference bind=\"setBluetoothLeIBeaconService\" \n cardinality=\"1..1\" \n interface=\"org.eclipse.kura.ble.ibeacon.BluetoothLeIBeaconService\" \n name=\"BluetoothLeIBeaconService\" \n policy=\"static\" \n unbind=\"unsetBluetoothLeIBeaconService\"/>\n
The BluetoothLeService is used to get the BluetoothLeAdapter to be used with the BluetoothLeIBeaconScanner and BluetoothLeIBeaconAdvertiser. As explained here, the adapter can be retrieved and powered on as follows:
this.bluetoothLeAdapter = this.bluetoothLeService.getAdapter(adapterName);\nif (this.bluetoothLeAdapter != null) {\n if (!this.bluetoothLeAdapter.isPowered()) {\n this.bluetoothLeAdapter.setPowered(true);\n }\n} \n
where adapterName is the name of the adapter, e.g. hci0.
"},{"location":"java-application-development/how-to-use-new-beacon-apis/#create-an-ibeacontm-advertiser","title":"Create an iBeacon\u2122 advertiser","text":"In order to properly configure an iBeacon\u2122 advertiser, a BluetoothLeIBeaconService is needed to create a new BluetoothLeIBeaconAdvertiser instance bound to a specific Bluetooth adapter:
try {\n BluetoothLeBeaconAdvertiser<BluetoothLeIBeacon> advertiser = this.bluetoothLeIBeaconService.newBeaconAdvertiser(this.bluetoothLeAdapter);\n} catch (KuraBluetoothBeaconAdvertiserNotAvailable e) {\n logger.error(\"Beacon Advertiser not available on {}\", this.bluetoothLeAdapter.getInterfaceName(),e);\n}\n
Then a BluetoothLeIBeacon object should be created, containing all the information to be broadcasted. In the following snippet, the BluetoothLeIBeacon object is instantiated and added to the advertiser. Then the broadcast time interval is set and the beacon advertising is started.
try {\n BluetoothLeIBeacon iBeacon = new BluetoothLeIBeacon(uuid, major, minor, txPower);\n advertiser.updateBeaconAdvertisingData(iBeacon);\n advertiser.updateBeaconAdvertisingInterval(minInterval, maxInterval;\n\n advertiser.startBeaconAdvertising();\n} catch (KuraBluetoothCommandException e) {\n logger.error(\"IBeacon configuration failed\", e);\n}\n
The BluetoothLeIBeacon represents the beacon packet that will be broadcasted by the advertiser and it should be configured will the following parameters:
Warning
Only one advertising packet can be broadcasted at a time on a specific Bluetooth adapter.
Finally, in the following snippet the advertiser is stopped and removed from the BluetoothLeIBeaconService:
try {\n advertiser.stopBeaconAdvertising();\n this.bluetoothLeIBeaconService.deleteBeaconAdvertiser(advertiser);\n} catch (KuraBluetoothCommandException e) {\n logger.error(\"Stop iBeacon advertising failed\", e);\n}\n
"},{"location":"java-application-development/how-to-use-new-beacon-apis/#create-an-ibeacontm-scanner","title":"Create an iBeacon\u2122 scanner","text":"As done for the advertiser, a BluetoothLeIBeaconService is needed to create a new BluetoothLeIBeaconScanner instance bound to a specific Bluetooth adapter:
bluetoothLeBeaconScanner<BluetoothLeIBeacon> scanner = this.bluetoothLeIBeaconService.newBeaconScanner(this.bluetoothLeAdapter);\n
A BluetoothLeIBeaconScanner needs a listener to collect the iBeacon packets that the Bluetooth adapter detects. In the following snippet, a simple listener that prints the iBeacon packet configuration is added to the scanner object:
private class iBeaconListener implements BluetoothLeBeaconListener<BluetoothLeIBeacon> {\n\n @Override\n public void onBeaconsReceived(BluetoothLeIBeacon beacon) {\n logger.info(\"iBeacon received from {}\", beacon.getAddress());\n logger.info(\"UUID : {}\", beacon.getUuid());\n logger.info(\"Major : {}\", beacon.getMajor());\n logger.info(\"Minor : {}\", beacon.getMinor());\n logger.info(\"TxPower : {}\", beacon.getTxPower());\n logger.info(\"RSSI : {}\", beacon.getRssi()); \n }\n\n}\n
scanner.addBeaconListener(listener);\n
The scanner is started for a specific time interval (in this case 10 seconds):
scanner.startBeaconScan(10);\n
Finally the scanner should be stopped, if needed, and the resources are released:
if (scanner.isScanning()) {\n scanner.stopBeaconScan();\n}\nscanner.removeBeaconListener(listener);\nthis.bluetoothLeIBeaconService.deleteBeaconScanner(scanner);\n
Note
The kura.legacy.bluetooth.beacon.scan property in the kura.properties file defines how the scan for beacons is performed. If set to true, the deprecated hcitool command is used. This guarantees that all the advertisement packets are reported. If set to false, the library will communicate to the OS using dbus. In the latter case, the rate of reports is limited and not all the advertisement packets are reported.
"},{"location":"java-application-development/how-to-use-new-beacon-apis/#how-to-use-kura-eddystonetm-apis","title":"How to use Kura Eddystone\u2122 APIs","text":"Eddystone\u2122 is a protocol specification that defines a BLE message format for proximity beacon messages. It describes several different frame types that may be used individually or in combinations to create beacons that can be used for a variety of applications. For more information please see here and here.
In this section the Eddystone\u2122 implementation of the Kura Beacon APIs is presented, providing several code snippets to explain how to perform common operations on them. For a complete example on Eddystone\u2122 advertising and scanning, please refer to the new Eddystone\u2122 advertiser and Eddystone\u2122 scanner examples.
Warning
Only Eddystone UID and URL frame types are currently supported.
As done with the iBeacon\u2122 implementation, an application has to bind the BluetoothLeService and BluetoothLeEddystoneService OSGI services, as shown in the following Java snippet:
public void setBluetoothLeService(BluetoothLeService bluetoothLeService) {\n this.bluetoothLeService = bluetoothLeService;\n}\n\npublic void unsetBluetoothLeService(BluetoothLeService bluetoothLeService) {\n this.bluetoothLeService = null;\n}\n\npublic void setBluetoothLeEddystoneService(BluetoothLeEddystoneService bluetoothLeEddystoneService) {\n this.bluetoothLeEddystoneService = bluetoothLeEddystoneService;\n}\n\npublic void unsetBluetoothLeEddystoneService(BluetoothLeEddystoneService bluetoothLeEddystoneService) {\n this.bluetoothLeEddystoneService = null;\n}\n
and in the component definition:
<reference bind=\"setBluetoothLeService\" \n cardinality=\"1..1\" \n interface=\"org.eclipse.kura.bluetooth.le.BluetoothLeService\" \n name=\"BluetoothLeService\" \n policy=\"static\" \n unbind=\"unsetBluetoothLeService\"/>\n\n<reference bind=\"setBluetoothLeEddystoneService\" \n cardinality=\"1..1\" \n interface=\"org.eclipse.kura.ble.eddystone.BluetoothLeEddystoneService\" \n name=\"BluetoothLeEddystoneService\" \n policy=\"static\" \n unbind=\"unsetBluetoothLeEddystoneService\"/>\n
The BluetoothLeService is used to get the BluetoothLeAdapter to be used with the BluetoothLeEddystoneScanner and BluetoothLeEddystoneAdvertiser. As explained here, the adapter can be retrieved and powered on as follows:
this.bluetoothLeAdapter = this.bluetoothLeService.getAdapter(adapterName);\nif (this.bluetoothLeAdapter != null) {\n if (!this.bluetoothLeAdapter.isPowered()) {\n this.bluetoothLeAdapter.setPowered(true);\n }\n} \n
where adapterName is the name of the adapter, e.g. hci0.
"},{"location":"java-application-development/how-to-use-new-beacon-apis/#create-an-eddystonetm-advertiser","title":"Create an Eddystone\u2122 advertiser","text":"In order to properly configure an Eddystone\u2122 advertiser, a BluetoothLeEddystoneService is needed to create a new BluetoothLeEddystoneAdvertiser instance bound to a specific Bluetooth adapter:
try {\n BluetoothLeBeaconAdvertiser<BluetoothLeEddystone> advertiser = this.advertising = this.bluetoothLeEddystoneService.newBeaconAdvertiser(this.bluetoothLeAdapter);\n} catch (KuraBluetoothBeaconAdvertiserNotAvailable e) {\n logger.error(\"Beacon Advertiser not available on {}\", this.bluetoothLeAdapter.getInterfaceName(),e);\n}\n
The advertiser has to be configured with a BluetoothLeEddystone object that contains all the information to be broadcasted. Currently, UID and URL frame types are supported. A UID frame can be created as follows:
BluetoothLeEddystone eddystone = new BluetoothLeEddystone();\neddystone.configureEddystoneUIDFrame(namespace, instance, txPower);\n
where namespace and instance are respectively 10-byte and 6-byte long sequences that compose a unique 16-byte Beacon ID. The txPower is the calibrated transmission power at 0 m.
A URL frame is created as follows:
BluetoothLeEddystone eddystone = new BluetoothLeEddystone();\neddystone.configureEddystoneURLFrame(url, txPower);\n
where url is the URL to be broadcasted and the txPower is the calibrated transmission power at 0 m.
After the BluetoothLeEddystone creation, the packet is added to the advertiser and the broadcast time interval is set. Then the advertiser is started:
try {\n advertiser.updateBeaconAdvertisingData(eddystone);\n advertiser.updateBeaconAdvertisingInterval(this.options.getMinInterval(), this.options.getMaxInterval());\n advertiserstartBeaconAdvertising();\n} catch (KuraBluetoothCommandException e) {\n logger.error(\"Eddystone configuration failed\", e);\n}\n
Finally, in the following snippet the advertiser is stopped and removed from the BluetoothLeEddystoneService:
try {\n advertiser.stopBeaconAdvertising();\n this.bluetoothLeEddystoneService.deleteBeaconAdvertiser(advertiser);\n} catch (KuraBluetoothCommandException e) {\n logger.error(\"Stop Advertiser advertising failed\", e);\n}\n
"},{"location":"java-application-development/how-to-use-new-beacon-apis/#create-an-eddystonetm-scanner","title":"Create an Eddystone\u2122 scanner","text":"As done for the advertiser, a BluetoothLeEddystoneService is needed to create a new BluetoothLeEddystoneScanner instance bound to a specific Bluetooth adapter:
bluetoothLeBeaconScanner<BluetoothLeEddystone> scanner = this.bluetoothLeEddystoneService.newBeaconScanner(this.bluetoothLeAdapter);\n
A BluetoothLeEddystoneScanner needs a listener to collect the Eddystone packets that the Bluetooth adapter detects. In the following snippet, a simple listener that detects the frame type and prints the packet content is added to the scanner object:
private class EddystoneListener implements BluetoothLeBeaconListener<BluetoothLeEddystone> {\n\n @Override\n public void onBeaconsReceived(BluetoothLeEddystone beacon) {\n logger.info(\"Eddystone {} received from {}\", eddystone.getFrameType(), eddystone.getAddress());\n if (\"UID\".equals(eddystone.getFrameType())) {\n logger.info(\"Namespace : {}\", bytesArrayToHexString(eddystone.getNamespace()));\n logger.info(\"Instance : {}\", bytesArrayToHexString(eddystone.getInstance()));\n } else if (\"URL\".equals(eddystone.getFrameType())) {\n logger.info(\"URL : {}\", eddystone.getUrlScheme() + eddystone.getUrl());\n }\n logger.info(\"TxPower : {}\", eddystone.getTxPower());\n logger.info(\"RSSI : {}\", eddystone.getRssi()); \n }\n\n}\n
scanner.addBeaconListener(listener);\n
The scanner is started for a specific time interval (in this case 10 seconds):
scanner.startBeaconScan(10);\n
Finally the scanner should be stopped, if needed, and the resources are released:
if (scanner.isScanning()) {\n scanner.stopBeaconScan();\n}\nscanner.removeBeaconListener(listener);\nthis.bluetoothLeEddystoneService.deleteBeaconScanner(scanner);\n
Note
The kura.legacy.bluetooth.beacon.scan property in the kura.properties file defines how the scan for beacons is performed. If set to true, the deprecated hcitool command is used. This guarantees that all the advertisement packets are reported. If set to false, the library will communicate to the OS using dbus. In the latter case, the rate of reports is limited and not all the advertisement packets are reported.
"},{"location":"java-application-development/how-to-use-new-beacon-apis/#add-new-beacon-apis-implementation","title":"Add new Beacon APIs implementation","text":"Eclipse Kura offers the implementation for iBeacon\u2122 and Eddystone\u2122 protocols, but it is possible to add implementations of different kinds of beacon protocols.
The org.eclipse.kura.bluetooth.le.beacon package contains the interfaces used by the beacon implementations:
The BluetoothLeBeaconManager, BluetoothLeBeaconScanner and BluetoothLeBeaconAdvertiser interfaces handles generic BluetoothLeBeacon objects and their implementations are provided by the org.eclipse.kura.ble.provider. The others interfaces, instead, are Beacon specific and their implementations depend on the specific protocol that is used. As a consequence, who wants to support a new Beacon protocol, should provide the implementation of the BluetoothLeBeaconService, BluetoothLeBeaconEncoder and BluetoothLeBeaconDecoder interfaces and extend the BluetoothLeBeacon class.
As an example, the org.eclipse.kura.ble.ibeacon.provider provides the implementation of the above APIs for the iBeacon\u2122 protocol. In this case, the org.eclipse.kura.ble.ibeacon package contains the following:
The org.eclipse.kura.internal.ble.ibeacon provides the implementations for the above interfaces:
The following image shows the UML diagram.
"},{"location":"java-application-development/how-to-use-new-bt-le-apis/","title":"How to Use New Bluetooth LE APIs","text":""},{"location":"java-application-development/how-to-use-new-bt-le-apis/#overview","title":"Overview","text":"Starting from version 3.1.0, Eclipse Kura implements a new set of APIs for managing Bluetooth Low Energy and Beacon devices. The new APIs replace the existing Bluetooth APIs, but the old ones are still available and can be used. So, the applications developed before Kura 3.1.0 continue to work.
The purpose of the new BLE APIs is to simplify the development of applications that interact with Bluetooth LE devices, offering clear and easy-to-use methods, and add new features to correctly manage the connection with remote devices. Moreover, the APIs organize the methods in a logical way to access all levels of a GATT client, from GATT services to GATT characteristics and descriptors, using UUIDs to identify the correct resource.
"},{"location":"java-application-development/how-to-use-new-bt-le-apis/#bluez-dbus-ble-gatt-api","title":"Bluez-Dbus - BLE GATT API","text":"The implementation of the new Kura BLE APIs is based on the Bluez-Dbus library that provides an easy to use Bluetooth LE API based on BlueZ over DBus. The library eases the access to GATT services and the management of BLE connections and discovery, without using any wrapper library as it is based on a newer version of dbus-java which uses jnr-unixsocket.
"},{"location":"java-application-development/how-to-use-new-bt-le-apis/#apis-description","title":"APIs description","text":"The new BLE APIs are exported in the org.eclipse.kura.bluetooth.le package. The interfaces are briefly described in the following.
More information about the APIs can be found in API Reference.
"},{"location":"java-application-development/how-to-use-new-bt-le-apis/#how-to-use-the-kura-ble-api","title":"How to use the Kura BLE API","text":"This section briefly presents how to use the Kura BLE APIs, providing several code snippets to explain how to perform common bluetooth operations. For a complete example, please refer to the new SensorTag application.
An application that wants to use the Kura BLE APIs should bind the BluetoothLeService OSGI service, as shown in the following Java snippet:
public void setBluetoothLeService(BluetoothLeService bluetoothLeService) {\n this.bluetoothLeService = bluetoothLeService;\n}\n\npublic void unsetBluetoothLeService(BluetoothLeService bluetoothLeService) {\n this.bluetoothLeService = null;\n}\n
and in the component definition:
<reference bind=\"setBluetoothLeService\" \n cardinality=\"1..1\" \n interface=\"org.eclipse.kura.bluetooth.le.BluetoothLeService\" \n name=\"BluetoothLeService\" \n policy=\"static\" \n unbind=\"unsetBluetoothLeService\"/>\n
"},{"location":"java-application-development/how-to-use-new-bt-le-apis/#get-the-bluetooth-adapter","title":"Get the Bluetooth adapter","text":"Once bound to the BluetoothLeService, an application can get the Bluetooth adapter and power on it, if needed:
this.bluetoothLeAdapter = this.bluetoothLeService.getAdapter(adapterName);\nif (this.bluetoothLeAdapter != null) {\n if (!this.bluetoothLeAdapter.isPowered()) {\n this.bluetoothLeAdapter.setPowered(true);\n }\n} \n
where adapterName is the name of the adapter, i.e. hci0.
"},{"location":"java-application-development/how-to-use-new-bt-le-apis/#search-for-ble-devices","title":"Search for BLE devices","text":"The BluetoothLeAdapter provides several methods to search for a device, a.k.a. perform a BLE discovery:
The following snippet shows how to perform a discovery of 10 seconds using findDevices method:
if (this.bluetoothLeAdapter.isDiscovering()) {\n try {\n this.bluetoothLeAdapter.stopDiscovery();\n } catch (KuraException e) {\n logger.error(\"Failed to stop discovery\", e);\n }\n}\nFuture<List<BluetoothLeDevice>> future = this.bluetoothLeAdapter.findDevices(10);\ntry {\n List<BluetoothLeDevice>; devices = future.get();\n} catch (InterruptedException | ExecutionException e) {\n logger.error(\"Scan for devices failed\", e);\n}\n
"},{"location":"java-application-development/how-to-use-new-bt-le-apis/#get-the-gatt-services-and-characteristics","title":"Get the GATT services and characteristics","text":"To get the GATT services using the BluetoothLeDevice, use the following snippet:
try {\n List<BluetoothLeGattService>; services = device.findServices();\n} catch (KuraBluetoothResourceNotFoundException e) {\n logger.error(\"Unable to find GATT services\", e);\n}\n
A specific GATT service can be retrieved using its UUID:
try {\n BluetoothLeGattService service = device.findService(uuid);\n} catch (KuraBluetoothResourceNotFoundException e) {\n logger.error(\"Unable to find GATT service\", e);\n}\n
Using the GATT service, it is possible to get a specific GATT characteristic (or the complete list) and the GATT descriptor from it:
try {\n BluetoothLeGattCharacteristic characteristic = service.findCharacteristic(characteristicUuid);\n BluetoothLeGattDescriptor descriptor = characteristic.findDescriptor(descriptorUuid);\n} catch (KuraBluetoothResourceNotFoundException e) {\n logger.error(\"Unable to find GATT resources\", e);\n}\n
"},{"location":"java-application-development/how-to-use-new-bt-le-apis/#io-operations-on-gatt-characteristics-and-descriptors","title":"IO operations on GATT characteristics and descriptors","text":"The Kura BLE APIs provides methods to manage the IO operations on GATT characteristics and descriptors. The following snippet provides an example on how to read and write data to a characteristic.
try {\n byte[] valueRead = characteristic.readValue();\n byte[] valueWrite = { 0x01};\n characteristic.writeValue(valueWrite);\n} catch (KuraBluetoothIOException e) {\n logger.error(\"IO operation failed\", e);\n}\n
In the following example, instead, a notification listener is configured to periodically receive the data from a GATT characteristic and print the first value of the given array. The period is internally set by the BLE device.
try {\n Consumer<byte[]>; callback = valueBytes -> System.out.println((int) valueBytes[0]);\n characteristic.enableValueNotifications(callback);\n} catch (KuraBluetoothNotificationException e) {\n logger.error();\n}\n
"},{"location":"java-application-development/how-to-use-new-bt-le-apis/#configure-bluez-on-the-raspberry-pi","title":"Configure Bluez on the Raspberry Pi","text":"The minimum version of Bluez supported by Kura Bluetooth LE APIs is 5.42. The Raspbian Stretch OS comes with Bluez 5.43, but older OS couldn't have an updated Bluez version. In this case, it is possible to compile and install Bluez from sources using a Raspberry Pi. The Bluez sources can be found here Proceed as follows:
sudo apt-get install libusb-dev libdbus-1-dev libglib2.0-dev libudev-dev libical-dev libreadline-dev\n
* Download bluez-5.43.tar.xz (or newer version) from here. * Decompress the compressed archive: tar -xf bluez-5.43.tar.x\n
cd bluez-5.43\n./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var --enable-library -disable-systemd --enable-experimental --enable-maintainer-mod\nmake\nmake install\n
"},{"location":"java-application-development/how-to-use-watchdog/","title":"How to use watchdog","text":""},{"location":"java-application-development/how-to-use-watchdog/#overview","title":"Overview","text":"When enabled, the watchdog is a peripheral monitor that will reboot the system if it is not refreshed during a certain time interval. In Kura, the WatchdogService can be used by critical applications. If the specified application is alive, the service notifies the watchdog; if the application is down, the service stops notifying the watchdog and a hardware reset occurs.
The WatchdogService notifies the kernel watchdog driver using the /dev/watchdog device file. You can verify that the watchdog driver is installed using the following command:
ls \u2013l /dev/watchdog\n
"},{"location":"java-application-development/how-to-use-watchdog/#configuration","title":"Configuration","text":"To configure the WatchdogService, select the WatchdogService option located in the Services area as shown in the screen capture below.
The WatchdogService provides the following configuration parameters:
enabled - sets whether or not this service is enabled or disabled. If enabled, you must set a pingInterval periodicity compatible with the watchdog driver.
pingInterval - specifies the time between two watchdog notifications. This time is hardware dependent. Generally, the maximum time between two notifications should be between 30 seconds and 1 minute. 10000 milliseconds for the pingInterval is typically a good choice.
The WatchdogService references a list of Critical Components that correspond to the applications implementing the CriticalComponent interface.
CriticalComponent is an interface that can be used to denote a component that is crucial to system operations. If a component implements CriticalComponent, then it must state its name as well as its criticalComponentTimeout. The name is a unique identifier in the system. The timeout is the length of time in milliseconds that the CriticalComponent must \"check in\" with the WatchdogService. If the CriticalComponent extends beyond the period of time specified in this timeout, a system reboot will be performed based on the WatchdogService configuration.
If at least one of the registered CriticalComponents has not \"checked in\" during the pingInterval time, the WatchdogService stops notifying the watchdog driver. The system reboots when the time interval reaches the hardware time that is programmed for the watchdog. When the WatchdogService is enabled and no application is using it, the service runs silently in the background.
An example of the WatchdogService can be found here.
The following code snippets demonstrate how to implement the CriticalComponent interface:
public class ModbusManager implements ConfigurableComponent, CriticalComponent, CloudClientListener\n
Registration of the class in WatchdogService::
if(m_watchdogService!=null){\n m_watchdogService.registerCriticalComponent(this);\n}\n
Periodic call to checkin method of WatchdogService in the main loop (keeps watchdog notification alive):
if(m_watchdogService!=null){\n m_watchdogService.checkin(this);\n}\n
"},{"location":"java-application-development/kura-workspace-setup/","title":"Kura Workspace Setup","text":"This document describes how to set up the Eclipse Kura workspace development environment, which consists of the following components:
This setup will allow you to develop applications or bundles running on Eclipse Kura. It will install only the APIs and the examples. If you want to contribute to the Eclipse Kura project follow this guide instead.
The Eclipse Kura development environment may be installed on Windows, Linux, or Mac OS. The setup instructions will be the same across each OS though each system may have unique characteristics.
Info
The local emulation of Eclipse Kura code is only supported in Linux and Mac, not in Windows.
"},{"location":"java-application-development/kura-workspace-setup/#jvm-installation","title":"JVM Installation","text":"Download and install JDK SE 8 from the following links as appropriate for your OS.
For Windows and Linux users, the JDK can be downloaded from the following link: Java SE 8 Downloads. Use the latest version of the Java SE Development Kit and download the version appropriate for your system.
For additional information regarding the installation of Java 8 on all supported operating systems, see JDK 8 and JRE 8 Installation Guide.
"},{"location":"java-application-development/kura-workspace-setup/#installing-eclipse-ide","title":"Installing Eclipse IDE","text":"Before installing Eclipse, you should choose directory locations for the Eclipse install and its workspaces.
Info
The following points should be kept in mind regarding Eclipse installs and workspaces:
Download the current distribution of Eclipse for your OS from Eclipse official website. Choose the Eclipse IDE for Eclipse Committers.
The zipped Eclipse file will be downloaded to the local file system and can be saved to a temporary location that can be deleted after Eclipse has been installed. After the file has been downloaded, it should be extracted to the Eclipse installs directory. The following screen capture shows the installation in Linux using an eclipse\\installs directory. The Eclipse executable will then be found in the eclipse\\installs\\eclipse directory. This installation will be different depending on the operating system.
Because there may potentially be future Eclipse installs extracted into this location, before doing anything else, rename the directory, such as eclipse\\installs\\juno1\\.
Warning
Once you begin using this Eclipse install, it should NOT be moved or renamed.
"},{"location":"java-application-development/kura-workspace-setup/#workspaces","title":"Workspaces","text":""},{"location":"java-application-development/kura-workspace-setup/#creating-an-eclipse-workspace","title":"Creating an Eclipse Workspace","text":"Run Eclipse by clicking its executable in the install directory.
When Eclipse is run for the first time, a workspace needs to be created. A single workspace will contain all the Java code/projects/bundles, Eclipse configuration parameters, and other relevant files for a specific business-level product. If the Use this as the default option is selected, the designated workspace becomes the default each time you run Eclipse.
If a workspace has not already been defined, or if you are creating a different workspace for another development project, enter a new workspace name. The workspace should be named appropriate to the project/product being developed.
Warning
Once you begin using a particular workspace, it should NOT be moved or renamed at any time.
Otherwise, select an existing workspace and click OK. After Eclipse is running, you can select the Eclipse menu File | Switch Workspace | Other to create or open a different workspace.
After the new workspace opens, click the Workbench icon to display the development environment.
Info
Additional workspace configuration:
lifecycle-mapping-metadata.xml
in Eclipse Kura workspace. You can find the file in the Windows -> Preferences -> Maven -> Lifecycle Mappings -> Open workspace lifecycle mappings metadata. After editing the file, reload it by pressing the \"Reload workspace lifecycle mappings metadata\" button. <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<lifecycleMappingMetadata>\n <lifecycleMappingFilters>\n <lifecycleMappingFilter>\n <symbolicName>org.eclipse.m2e.pde.connector</symbolicName>\n <versionRange>[2.1.2,)</versionRange>\n <packagingTypes>\n <packagingType>eclipse-test-plugin</packagingType>\n <packagingType>eclipse-plugin</packagingType>\n <packagingType>eclipse-feature</packagingType>\n </packagingTypes>\n </lifecycleMappingFilter>\n </lifecycleMappingFilters>\n</lifecycleMappingMetadata>\n
eclipse-tycho
plugin following this steps:Work with:
text field -> expand the category and select the Tycho Project Configurators Feature
and proceed with the installation.To set up your Eclipse Kura project workspace, you will need to download the Eclipse Kura User Workspace archive from Eclipse Kura Download Page.
From the Eclipse File menu, select the Import option. In the Import dialog box, expand the General heading, select Existing Projects into Workspace, and then click Next.
Now click the Select archive file option button and browse to the archive file, such as user_workspace_archive_.zip.
Finally, click Finish to import the projects. At this point, you should have four projects in your workspace. The four projects are as follows:
org.eclipse.kura.api \u2013 the core Eclipse Kura API.
org.eclipse.kura.demo.heater \u2013 an example project that you can use as a starting point for creating your own bundle.
org.eclipse.kura.emulator \u2013 the emulator project for running Eclipse Kura within Eclipse (Linux/Mac only).
target-definition \u2013 a set of required bundles that are dependencies of the APIs and Eclipse Kura.
Eclipse will also report some errors at this point. See the next section to resolve those errors.
"},{"location":"java-application-development/kura-workspace-setup/#workspace-setup","title":"Workspace Setup","text":"This section will guide the users to configure the development workspace environment.
"},{"location":"java-application-development/kura-workspace-setup/#jre-configuration","title":"JRE Configuration","text":"The latest Eclipse IDEs require and configure, by default, a Java 11 environment. In order to be able to leverage and develop using the new workspace for Eclipse Kura, the user will be required to perform a one-time operation to specify to the IDE a Java 8 JDK. Opening the Eclipse preferences and selecting the Installed JREs in the Java section, the user has to select an installed Java 8 instance.
After applying the configuration change, the user will be prompted to align also the compiler options. To do so, selecting the Compiler entry in the Java section, the user has to select 1.8 from the list of available Java versions.
After applying the changes, the user will be prompted to recompile the environment.
"},{"location":"java-application-development/kura-workspace-setup/#target-definition-setup","title":"Target Definition Setup","text":"Click the arrow next to the target-definition project in the workspace and double-click kura-equinox_.target to open it.
In the Target Definition window, click the link Set as Target Platform. Doing so will reset the target platform, rebuild the Eclipse Kura projects, and clear the errors that were reported. At this point, you are ready to begin developing Eclipse Kura-based applications for your target platform.
"},{"location":"java-application-development/kura-workspace-setup/#run-the-eclipse-kura-emulator","title":"Run the Eclipse Kura Emulator","text":"To start the Eclipse Kura emulator, select the \"Eclipse Kura Emulator.launch\" profile from \"Other Projects\" -> \"setups\" -> \"launchers\" and open it with \"Run as\" -> \"Run Configurations...\". Then click on the \"Arguments\" tab and update the \"VM arguments\" as follows to adapt the paths to the folder structure created by the Oomph installer:
-Dkura.have.net.admin=false -Dorg.osgi.framework.storage=/tmp/osgi/framework_storage -Dosgi.clean=true -Dosgi.noShutdown=true -Declipse.ignoreApp=true -Dorg.eclipse.kura.mode=emulator -Dkura.configuration=file:${workspace_loc}/../git/kura/kura/emulator/org.eclipse.kura.emulator/src/main/resources/kura.properties -Ddpa.configuration=/tmp/kura/dpa.properties -Dlog4j.configurationFile=file:${workspace_loc}/../git/kura/kura/emulator/org.eclipse.kura.emulator/src/main/resources/log4j.xml -Dkura.data=${workspace_loc}/kura/data -Dkura.snapshots=${workspace_loc}/kura/user/snapshots -Dorg.eclipse.equinox.http.jetty.customizer.class=org.eclipse.kura.jetty.customizer.KuraJettyCustomizer\n
The Eclipse Kura Web UI will be available at the following URL: http://127.0.0.1:8080 with username and password admin.
"},{"location":"java-application-development/ram-usage-considerations/","title":"RAM Usage Considerations","text":"During application development and before moving to production, it is advisable to understand if the amount of free RAM available on the device is enough for correct device operation.
Since RAM usage is application dependent, it is important to perform some stress tests to bring the device in the worst case conditions and verify system behavior.
Some of the aspects that should be taken into account are the following:
"},{"location":"java-application-development/ram-usage-considerations/#java-heap-memory-usage","title":"Java Heap memory usage","text":"Java heap is used to store the Java objects and classes at runtime.
The heap should be:
The size of the heap is controlled by the -Xms
and -Xmx
Java command line arguments. These parameters are defined in the /opt/eclipse/kura/bin/start_kura_debug.sh
(for development mode) and /opt/eclipse/kura/bin/start_kura_background.sh
(for production mode).
The -Xms
parameter defines the initial size of Java heap and -Xmx
defines the maximum size. The JVM will start using Xms
as the size of the heap, and then it will grow the heap at runtime up to Xmx
if needed, depending on application memory demand.
Resizing the heap has a cost in terms of performance, for this reason Xms
and Xmx
are set to the same size by default on most platforms.
In order to understand if the heap is large enough, it is advisable to perform a stress test simulating the conditions of maximum memory demand by the applications running inside Kura. For example, if a in-memory database instance is used by a DataService instance, during the test the database can be filled up to the maximum capacity to verify if this causes any issue.
Regarding point 2., it should be noted that heap memory is not necessarily backed by physical memory immediately after JVM startup. Even if the JVM performs an allocation of size Xmx
immediately, physical memory will be assigned to the Java process by the kernel only when the memory pages are actually accessed by the JVM.
For this reason the amount of physical memory used by the JVM might appear small right after system boot and grow with time, up to the maximum size. This can happen even if the applications running inside Kura do not have high memory requirements, and can lead to potential issues that show up only after some time.
In order to recreate such issues, the -XX:+AlwaysPreTouch
JVM command line option can be used during development to force the JVM to access all heap memory after start, causing the JVM process to use the maximum amount of physical memory immediately.
Another aspect that can lead to RAM related issues is logging. As a general rule, it is recommended to reduce the amount of log messages produced by Kura during normal operation.
Kura default logging configuration (/opt/eclipse/kura/log4j/log4j.xml
) depends on the platform.
The size of the files in the /var/log
directory will be checked periodically and the files will be rotated to the persisted /var/old_logs
directory if needed.
If external applications are installed on the system (e.g. Docker containers), their RAM usage should be analyzed as well.
Stress tests related to Java heap size, log size and external applications can be run simultaneously to simulate a worst case scenario.
"},{"location":"java-application-development/remote-debugging-on-target-platform/","title":"Remote debugging on target platform","text":"Eclipse Kura can be started with Java Debug Wire Protocol (JDWP) support, allowing the remote debugging of the developed application using Eclipse IDE. The procedure for remote debugging is presented in the following.
Connect to the target platform (i.e. RaspberryPi) and stop the Kura application typing sudo systemctl stop kura
or sudo /etc/init.d/kura stop
.
Start Kura with Java Debug Wire Protocol (JDWP) typing sudo /opt/eclipse/kura/bin/start_kura_debug.sh
. This will start Kura and open an OSGi console. It will also start listening for socket connections on port 8000.
Warning
Starting from Java 9, the JDWP socket connector accepts only local connections by default (see here for further details). To enable remote debugging on Java 9, the following line in /opt/eclipse/kura/bin/start_kura_debug.sh
: -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n \\has to be replaced with the following one: -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=*:8000,suspend=n \\
Open the tcp port 8000 in the firewall. This can be done through the firewall tab in Kura web interface or using iptables.
Install your application bundle on the target platform.
From Eclipse IDE, set a breakpoint in the application code at a point that will be reached (i.e. activation method, common logging statement, etc.). Then:
Click Debug
Eclipse will connect to the target platform VM and switch to the Debug Perspective when the breakpoint will have been hit.
To stop the remote debugging, select the \u201cDisconnect\u201d button from the Debug Perspective.
An Asset can be used inside a Wire Graph, in this case it is represented as node with two ports an input port and an output port. An Asset used in this way is called WireAsset.
"},{"location":"kura-wires/assets-as-wire-components/#read-mode","title":"Read mode","text":"Every time a WireAsset receives an envelope on its input port, it will read the values of all of its channels with READ
or READ_WRITE
type. The result is emitted as a WireEnvelope with a single WireRecord. The WireRecord contains the following properties:
assetName
, value type STRING and the emitting asset asset name as value For each channel in asset configuration with READ or READ_WRITE type named name:<name>_timestamp
value type = LONG
reporting a timestamp in milliseconds since UNIX epoch. This property will be present only if the timestamp.mode Asset configuration property is set to PER_CHANNEL
<name>_error
, value type = STRING
reporting an error message. This property will be present only if read operation fails and the emit.errors Asset configuration property is set to true.For example, if the Asset attached to the Modbus Driver shown in the picture below receives a WireEnvelope on its input port, it can emit an envelope with the following content, assuming that the read operation for each channel succeed:
modbusAsset
(type = STRING
)true
(type = BOOLEAN
)1597925188
(type = LONG
)false
(type = BOOLEAN
)1597925188
(type = LONG
)true
(type = BOOLEAN
)1597925188
(type = LONG
)false
(type = BOOLEAN
)1597925188
(type = LONG
)false
(type = BOOLEAN
)1597925188
(type = LONG
)true
(type = BOOLEAN
)1597925188
(type = LONG
)true
(type = BOOLEAN
)1597925188
(type = LONG
)false
(type = BOOLEAN
)1597925188
(type = LONG
)true
(type = BOOLEAN
)1597925188
(type = LONG
)123
(type = INTEGER
)1597925188
(type = LONG
)11
(type = INTEGER
)1597925188
(type = LONG
)false
(type = BOOLEAN
)1597925188
(type = LONG
)false
(type = BOOLEAN
)1597925188
(type = LONG
)The emitted WireEnvelope contains a single record containing the properties described above.
The Logger WireComponent can be used to inspect the messages emitted on a specific output port of a WireComponent by creating a connection between the output port of the component to the input port of the Logger. In this case the content of the received envelopes will be printed on device log (/var/log/kura.log
).
As mentioned above, the read operation is performed only if an envelope is received on the input port of the WireAsset. In order to achieve this, another component must be connected to the input port of the WireAsset.
An example of such component can be the Timer, this component can be configured to periodically emit an envelope containing a single wire record with a single property named TIMER reporting the current UNIX timestamp. Connecting this component to a WireAsset allows to implement a simple read polling cycle. The configuration of the timer defines the polling interval.
"},{"location":"kura-wires/assets-as-wire-components/#listen-mode","title":"Listen mode","text":"Enabling the listen flag allows to enable unsolicited notifications from the driver.
When this happens, the Asset will emit an WireEnvelope containing the updated value for the channel involved in the event. The content of this envelope is the same as the one generated in case of a read operation on the channel.
For example if listen is ticked for LED1 and the driver above detects a value change in that channel, the Asset will emit the following envelope:
modbusAsset
(type = STRING
)false
(type = BOOLEAN
)1597925200
(type = LONG
)This mode does not require to connect any component to the input port of the driver. The conditions that trigger the events for the channels and their meaning is reported in the Driver specific documentation.
Note: The example above is not completely realistic since the Modbus driver does not support listen mode. In this case ticking the listen flag will have no effect. The support for listen mode is mentioned in driver documentation.
Listen mode and Read mode are not mutually exclusive. If a channel is defined as READ
or READ_WRITE
and the listen flag is ticked, the driver will emit the channel value when a WireEnvelope is received on its input port or when a driver event is generated.
Additionally, the Wire Graph can also be used to update asset values through write operations, according to the following rule.
Every time a WireAsset receives an envelope on its input port, for each property contained in the received WireRecords with key <key>
, value type <value type>
and value <value>
, the driver will perform this operation: If a channel with name <key>
is defined in asset configuration whose value.type is equal to <value type>
and type is WRITE
or READ_WRITE
, then the Asset will write <value>
to the channel.
For example if the Asset above receives the following envelope:
false
(type = BOOLEAN
)78
(type = LONG
)true
(type = BOOLEAN
)bar
(type = STRING
)The following operations will happen:
BOOLEAN
, and type = READ_WRITE
, the driver will write false
to that channel for the rule mentioned above.78
property will have no effect, since the Asset configuration contains a channel named LED2 with type = READ_WRITE
, but value.type = BOOLEAN
!= LONG
.true
property will have no effect, since the asset contains a channel named Toggle-4
, with value.type = BOOLEAN
but type = READ
!= WRITE
| READ_WRITE
bar
property will have no effect, since none of the defined channels has foo
as name.READ
or READ_WRITE
, since a WireEnvelope has been received.The Wires feature aims to simplify the development of IoT Edge Computing Applications leveraging reusable configurable components that can be wired together and which, eventually, allows configurable cooperation between these components.
In the dataflow programming model, the application logic is expressed as a directed graph (flow) where each node can have inputs, outputs, and independent processing units. There are nodes that only produce outputs and ones that only consume inputs, which usually represent the start and the end of the flow. The inner-graph nodes process the inputs and produce outputs for downstream nodes. The processing unit of a node executes independently and does not affect the execution of other nodes. Thus, the nodes are highly reusable and portable.
In this way, the developer can easily prototype its solution without sacrificing flexibility and working at a high level of abstraction: the graph can be extended adding new nodes or drawing new connections. Furthermore, the developer can take advantage of the Eclipse Marketplace integration, being able to use open source or commercial building blocks into the final solution, by simply dragging and dropping a link to the Eclipse Marketplace in the Administrative Web UI.
"},{"location":"kura-wires/introduction/#data-model","title":"Data Model","text":"The communication over a single graph edge (Wire) is message oriented, messages are called WireEnvelopes. Each WireEnvelope contains a list of WireRecords. Each WireRecord contains a set of key-value pairs, called properties, the property key is always a string and it is unique within the same record, the property value can have one of the following types:
The Wire Composer is the main source of interaction with the Wires framework. It is accessible by clicking on the Wires button under System.
The Wires page is composed by a central composer, where the graph can be actually designed, a lower part that is populated when a wire component is clicked and that allows to update the component configuration and a section in the right with the available Wire Components.
"},{"location":"kura-wires/introduction/#wire-components","title":"Wire Components","text":"The following components are distributed with Kura:
In the top left part of the Wires page the Download button allows to download the configuration of the graph and of all the components that are part of the graph.
This snapshot can be used to replicate the same configuration across all the fleet of devices.
To upload the stored graph, the user has to access the Settings page and in the Snapshots section click the Upload and Apply button.
Warning
The graph configuration will be actually merged with the one existing. Be careful to Delete the existing graph and apply, if you don't want to merge with the existing Wires configuration.
"},{"location":"kura-wires/wire-graph-service-configuration-format/","title":"WireGraphService Configuration Format","text":"This document describes the configuration format for the WireGraphService component.
The WireGraphService configuration contains all the information related to the Wire Graph topology and rendering properties. The pid of the WireGraphService configuration is org.eclipse.kura.wire.graph.WireGraphService
.
The WireGraphService configuration represents the current graph layout as a single string typed property named WireGraph
that represents a serialized JSON representation of a WireGraph object.
An object representing a Wire Component position.
Properties:
number
number
{\n \"x\": 40,\n \"y\": 0\n}\n
{\n \"x\": 1.5\n}\n
{}\n
"},{"location":"kura-wires/wire-graph-service-configuration-format/#portnamelist","title":"PortNameList","text":"An object that specifies custom names for Wire Component input and output ports. The properties name for this object must be represented as an integer starting from 0, matching the index of the port whose name needs to be assigned. If the property name is not specified, the default port name will be used.
Properties:
string
The name for the port of index _portIndex{\n \"0\": \"foo\",\n \"1\": \"bar\"\n}\n
{}\n
"},{"location":"kura-wires/wire-graph-service-configuration-format/#renderingproperties","title":"RenderingProperties","text":"An object describing some Wire Component rendering parameters like position and custom port names.
Properties:
object
object
object
{\n \"inputPortNames\": {},\n \"outputPortNames\": {\n \"0\": \"foo\",\n \"1\": \"bar\"\n },\n \"position\": {\n \"x\": 40,\n \"y\": 0\n }\n}\n
{\n \"inputPortNames\": {},\n \"outputPortNames\": {\n \"0\": \"foo\",\n \"1\": \"bar\"\n }\n}\n
{\n \"position\": {\n \"x\": 40,\n \"y\": 0\n }\n}\n
{}\n
"},{"location":"kura-wires/wire-graph-service-configuration-format/#wirecomponent","title":"WireComponent","text":"An object that describes a Wire Component that is part of a Wire Graph
Properties:
string
The Wire Component pidnumber
An integer reporting the number of input ports of the Wire Component.number
An integer reporting the number of output ports of the Wire Component.object
{\n \"inputPortCount\": 1,\n \"outputPortCount\": 2,\n \"pid\": \"cond\",\n \"renderingProperties\": {\n \"inputPortNames\": {},\n \"outputPortNames\": {\n \"0\": \"foo\",\n \"1\": \"bar\"\n },\n \"position\": {\n \"x\": 40,\n \"y\": 0\n }\n }\n}\n
{\n \"inputPortCount\": 0,\n \"outputPortCount\": 1,\n \"pid\": \"timer\",\n \"renderingProperties\": {\n \"inputPortNames\": {},\n \"outputPortNames\": {},\n \"position\": {\n \"x\": -220,\n \"y\": -20\n }\n }\n}\n
"},{"location":"kura-wires/wire-graph-service-configuration-format/#wire","title":"Wire","text":"An object that describes a Wire connecting two Wire Components.
Properties:
string
The pid of the emitter component.number
The index of the output port of the emitter component that is connected to this Wire.string
The pid of the receiver component.number
The index of the input port of the receiver component that is connected to this Wire.{\n \"emitter\": \"timer\",\n \"emitterPort\": 0,\n \"receiver\": \"cond\",\n \"receiverPort\": 0\n}\n
"},{"location":"kura-wires/wire-graph-service-configuration-format/#wiregraph","title":"WireGraph","text":"An object that describes the topology and rendering properties of a Wire Graph
Properties:
array
The list of the wire components contained in the Wire Graphobject
array
The list of Wires contained in the Wire Graphobject
{\n \"components\": [\n {\n \"inputPortCount\": 0,\n \"outputPortCount\": 1,\n \"pid\": \"timer\",\n \"renderingProperties\": {\n \"inputPortNames\": {},\n \"outputPortNames\": {},\n \"position\": {\n \"x\": -220,\n \"y\": -20\n }\n }\n },\n {\n \"inputPortCount\": 1,\n \"outputPortCount\": 2,\n \"pid\": \"cond\",\n \"renderingProperties\": {\n \"inputPortNames\": {},\n \"outputPortNames\": {\n \"0\": \"foo\",\n \"1\": \"bar\"\n },\n \"position\": {\n \"x\": 40,\n \"y\": 0\n }\n }\n }\n ],\n \"wires\": [\n {\n \"emitter\": \"timer\",\n \"emitterPort\": 0,\n \"receiver\": \"cond\",\n \"receiverPort\": 0\n }\n ]\n}\n
"},{"location":"kura-wires/wire-service-references/","title":"References","text":"Additional information about Wires is available at the following resources:
"},{"location":"kura-wires/wire-service-references/#dzone","title":"DZONE","text":"The WIRE-V1 cloud request handler and the corresponding REST APIs allow to update, delete and get the current Wire Graph status. The request handler also supports creating, updating and deleting Asset and Driver instances and retrieving the metadata required for supporting Wire Graph editing applications.
The GET/graph/shapshot and PUT/graph/snapshot requests use the same format as the Wire Graph snapshot functionality of the Kura Web UI.
A Wire Graph snapshot can be obtained by navigating to the Wires section of Kura Web UI, clicking the Download button and selecting the JSON format.
Accessing the REST APIs requires to use an identity with the rest.wires.admin
permission assigned.
updateGraph
for the graph update operation, update:$pid
or delete:$pid
for update or delete operations performed on configurations not referenced by the Wire Graph, and snapshot
, for the snapshot creation operation. In case of an unexpected failure, a generic error response will be returned.response body :
Variants:
This request will replace the current graph topology with the received one. The received configuration must satisfy the following requirements. If any of the requirements is not met, the operation will fail and no changes will be applied to the system: * The configuration of the org.eclipse.kura.wire.graph.WireGraphService
component must be specified. * The configuration of the org.eclipse.kura.wire.graph.WireGraphService
component must contain a property named WireGraph
of STRING
type containing the graph layout as described in the WireGraphService document. * The inputPortCount
and outputPortCount
properties must be specified for all components in WireGraphService configuration. * The configuration of all components referenced by WireGraphService configuration that do not exist on target device must be specified. * The configuration of all components referenced by WireGraphService configuration that do not exist on target device must specify the service.factoryPid
configuration property reporting the component factory pid.
If a component already exists on the system and its configuration is supplied as part of the request, the component configuration will be updated. In this case the usual configuration merge semantics will be applied, the set of received properties will be merged with the existing one. The properties in the request body will overwrite the existing ones with the same name.
WireAsset configurations are treated sligtly differently, an update to a WireAsset configuration is performed by deleting the existing component and creating a new instance with the received configuration. This behavior is necessary in order to allow channel removal.
It is also allowed to specify Driver or Asset configurations that are not referenced by the Wire Graph included in the request body.
"},{"location":"kura-wires/wire-service-rest-v1/#delgraph","title":"DEL/graph","text":"delete:$pid
for delete operations, and snapshot
, for the snapshot creation operation. In case of an unexpected failure, a generic error response will be returned.response body :
Variants:
update:$pid
or delete:$pid
for update or delete operations, and snapshot
, for the snapshot creation operation. In case of an unexpected failure, a generic error response will be returned.response body :
Variants:
driverDescriptors
can be missing if no Driver instances exist on the system)wireComponentDefinitions
will be missing.wireComponentDefinitions
will be missing. If the metadata for a given factoryPid is not found, the request will succeed and it will not be included in the list.driverOCDs
will be missing.driverOCDs
will be missing. If the metadata for a given factoryPid is not found, the request will succeed and it will not be included in the list.driverChannelDescriptors
will be missing.driverChannelDescriptors
will be missing. If the metadata for a given pid is not found, the request will succeed and it will not be included in the list.A Wire Component definition object
Properties:
string
The component factory pidnumber
The minimum input port countnumber
The maximum number of input portsnumber
The default number of input portsnumber
The minimum number of output portsnumber
The maximum number of output portsnumber
The default number of output portsobject
object
array
object
{\n \"componentOCD\": [\n {\n \"cardinality\": 0,\n \"defaultValue\": \"50\",\n \"description\": \"The maximum number of envelopes that can be stored in the queue of this FIFO component\",\n \"id\": \"queue.capacity\",\n \"isRequired\": true,\n \"name\": \"queue.capacity\",\n \"type\": \"INTEGER\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"false\",\n \"description\": \"Defines the behavior in case of full queue: if set to true new envelopes will be dropped, otherwise, if an emitter delivers an envelope to this component it will block until the envelope can be successfully enqueued.\",\n \"id\": \"discard.envelopes\",\n \"isRequired\": true,\n \"name\": \"discard.envelopes\",\n \"type\": \"BOOLEAN\"\n }\n ],\n \"defaultInputPorts\": 1,\n \"defaultOutputPorts\": 1,\n \"factoryPid\": \"org.eclipse.kura.wire.Fifo\",\n \"maxInputPorts\": 1,\n \"maxOutputPorts\": 1,\n \"minInputPorts\": 1,\n \"minOutputPorts\": 1\n}\n
"},{"location":"kura-wires/wire-service-rest-v1/#driverchanneldescriptor","title":"DriverChannelDescriptor","text":"An object that describes Driver specific channel configuration properties
Properties:
string
The Driver pidstring
The Driver factory pidarray
object
{\n \"channelDescriptor\": [\n {\n \"cardinality\": 0,\n \"defaultValue\": \"AA:BB:CC:DD:EE:FF\",\n \"description\": \"sensortag.address\",\n \"id\": \"sensortag.address\",\n \"isRequired\": true,\n \"name\": \"sensortag.address\",\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"TEMP_AMBIENT\",\n \"description\": \"sensor.name\",\n \"id\": \"sensor.name\",\n \"isRequired\": true,\n \"name\": \"sensor.name\",\n \"option\": [\n {\n \"label\": \"TEMP_AMBIENT\",\n \"value\": \"TEMP_AMBIENT\"\n },\n {\n \"label\": \"TEMP_TARGET\",\n \"value\": \"TEMP_TARGET\"\n },\n {\n \"label\": \"HUMIDITY\",\n \"value\": \"HUMIDITY\"\n },\n {\n \"label\": \"ACCELERATION_X\",\n \"value\": \"ACCELERATION_X\"\n },\n {\n \"label\": \"ACCELERATION_Y\",\n \"value\": \"ACCELERATION_Y\"\n },\n {\n \"label\": \"ACCELERATION_Z\",\n \"value\": \"ACCELERATION_Z\"\n },\n {\n \"label\": \"MAGNETIC_X\",\n \"value\": \"MAGNETIC_X\"\n },\n {\n \"label\": \"MAGNETIC_Y\",\n \"value\": \"MAGNETIC_Y\"\n },\n {\n \"label\": \"MAGNETIC_Z\",\n \"value\": \"MAGNETIC_Z\"\n },\n {\n \"label\": \"GYROSCOPE_X\",\n \"value\": \"GYROSCOPE_X\"\n },\n {\n \"label\": \"GYROSCOPE_Y\",\n \"value\": \"GYROSCOPE_Y\"\n },\n {\n \"label\": \"GYROSCOPE_Z\",\n \"value\": \"GYROSCOPE_Z\"\n },\n {\n \"label\": \"LIGHT\",\n \"value\": \"LIGHT\"\n },\n {\n \"label\": \"PRESSURE\",\n \"value\": \"PRESSURE\"\n },\n {\n \"label\": \"GREEN_LED\",\n \"value\": \"GREEN_LED\"\n },\n {\n \"label\": \"RED_LED\",\n \"value\": \"RED_LED\"\n },\n {\n \"label\": \"BUZZER\",\n \"value\": \"BUZZER\"\n },\n {\n \"label\": \"KEYS\",\n \"value\": \"KEYS\"\n }\n ],\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"1000\",\n \"description\": \"notification.period\",\n \"id\": \"notification.period\",\n \"isRequired\": true,\n \"name\": \"notification.period\",\n \"type\": \"INTEGER\"\n }\n ],\n \"factoryPid\": \"org.eclipse.kura.driver.ble.sensortag\",\n \"pid\": \"sensortag\"\n}\n
"},{"location":"kura-wires/wire-service-rest-v1/#wiregraphmetadata","title":"WireGraphMetadata","text":"An object contiaining metatada describing Wire Components, Drivers and Assets
Properties:
array
object
array
object
array
object
array
object
{\n \"assetChannelDescriptor\": [\n {\n \"cardinality\": 0,\n \"defaultValue\": \"true\",\n \"description\": \"Determines if the channel is enabled or not\",\n \"id\": \"+enabled\",\n \"isRequired\": true,\n \"name\": \"enabled\",\n \"type\": \"BOOLEAN\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"Channel-1\",\n \"description\": \"Name of the Channel\",\n \"id\": \"+name\",\n \"isRequired\": true,\n \"name\": \"name\",\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"READ\",\n \"description\": \"Type of the channel\",\n \"id\": \"+type\",\n \"isRequired\": true,\n \"name\": \"type\",\n \"option\": [\n {\n \"label\": \"READ\",\n \"value\": \"READ\"\n },\n {\n \"label\": \"READ_WRITE\",\n \"value\": \"READ_WRITE\"\n },\n {\n \"label\": \"WRITE\",\n \"value\": \"WRITE\"\n }\n ],\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"INTEGER\",\n \"description\": \"Value type of the channel\",\n \"id\": \"+value.type\",\n \"isRequired\": true,\n \"name\": \"value.type\",\n \"option\": [\n {\n \"label\": \"BOOLEAN\",\n \"value\": \"BOOLEAN\"\n },\n {\n \"label\": \"BYTE_ARRAY\",\n \"value\": \"BYTE_ARRAY\"\n },\n {\n \"label\": \"DOUBLE\",\n \"value\": \"DOUBLE\"\n },\n {\n \"label\": \"INTEGER\",\n \"value\": \"INTEGER\"\n },\n {\n \"label\": \"LONG\",\n \"value\": \"LONG\"\n },\n {\n \"label\": \"FLOAT\",\n \"value\": \"FLOAT\"\n },\n {\n \"label\": \"STRING\",\n \"value\": \"STRING\"\n }\n ],\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"description\": \"Scale to be applied to the numeric value of the channel\",\n \"id\": \"+scale\",\n \"isRequired\": false,\n \"name\": \"scale\",\n \"type\": \"DOUBLE\"\n },\n {\n \"cardinality\": 0,\n \"description\": \"Offset to be applied to the numeric value of the channel\",\n \"id\": \"+offset\",\n \"isRequired\": false,\n \"name\": \"offset\",\n \"type\": \"DOUBLE\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"\",\n \"description\": \"Unit associated to the value of the channel\",\n \"id\": \"+unit\",\n \"isRequired\": false,\n \"name\": \"unit\",\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"false\",\n \"description\": \"Specifies if WireAsset should emit envelopes on Channel events\",\n \"id\": \"+listen\",\n \"isRequired\": true,\n \"name\": \"listen\",\n \"type\": \"BOOLEAN\"\n }\n ],\n \"driverChannelDescriptors\": [\n {\n \"channelDescriptor\": [\n {\n \"cardinality\": 0,\n \"defaultValue\": \"MyNode\",\n \"description\": \"node.id\",\n \"id\": \"node.id\",\n \"isRequired\": true,\n \"name\": \"node.id\",\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"2\",\n \"description\": \"node.namespace.index\",\n \"id\": \"node.namespace.index\",\n \"isRequired\": true,\n \"name\": \"node.namespace.index\",\n \"type\": \"INTEGER\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"DEFINED_BY_JAVA_TYPE\",\n \"description\": \"opcua.type\",\n \"id\": \"opcua.type\",\n \"isRequired\": true,\n \"name\": \"opcua.type\",\n \"option\": [\n {\n \"label\": \"DEFINED_BY_JAVA_TYPE\",\n \"value\": \"DEFINED_BY_JAVA_TYPE\"\n },\n {\n \"label\": \"BOOLEAN\",\n \"value\": \"BOOLEAN\"\n },\n {\n \"label\": \"SBYTE\",\n \"value\": \"SBYTE\"\n },\n {\n \"label\": \"INT16\",\n \"value\": \"INT16\"\n },\n {\n \"label\": \"INT32\",\n \"value\": \"INT32\"\n },\n {\n \"label\": \"INT64\",\n \"value\": \"INT64\"\n },\n {\n \"label\": \"BYTE\",\n \"value\": \"BYTE\"\n },\n {\n \"label\": \"UINT16\",\n \"value\": \"UINT16\"\n },\n {\n \"label\": \"UINT32\",\n \"value\": \"UINT32\"\n },\n {\n \"label\": \"UINT64\",\n \"value\": \"UINT64\"\n },\n {\n \"label\": \"FLOAT\",\n \"value\": \"FLOAT\"\n },\n {\n \"label\": \"DOUBLE\",\n \"value\": \"DOUBLE\"\n },\n {\n \"label\": \"STRING\",\n \"value\": \"STRING\"\n },\n {\n \"label\": \"BYTE_STRING\",\n \"value\": \"BYTE_STRING\"\n },\n {\n \"label\": \"BYTE_ARRAY\",\n \"value\": \"BYTE_ARRAY\"\n },\n {\n \"label\": \"SBYTE_ARRAY\",\n \"value\": \"SBYTE_ARRAY\"\n }\n ],\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"STRING\",\n \"description\": \"node.id.type\",\n \"id\": \"node.id.type\",\n \"isRequired\": true,\n \"name\": \"node.id.type\",\n \"option\": [\n {\n \"label\": \"NUMERIC\",\n \"value\": \"NUMERIC\"\n },\n {\n \"label\": \"STRING\",\n \"value\": \"STRING\"\n },\n {\n \"label\": \"GUID\",\n \"value\": \"GUID\"\n },\n {\n \"label\": \"OPAQUE\",\n \"value\": \"OPAQUE\"\n }\n ],\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"Value\",\n \"description\": \"attribute\",\n \"id\": \"attribute\",\n \"isRequired\": true,\n \"name\": \"attribute\",\n \"option\": [\n {\n \"label\": \"NodeId\",\n \"value\": \"NodeId\"\n },\n {\n \"label\": \"NodeClass\",\n \"value\": \"NodeClass\"\n },\n {\n \"label\": \"BrowseName\",\n \"value\": \"BrowseName\"\n },\n {\n \"label\": \"DisplayName\",\n \"value\": \"DisplayName\"\n },\n {\n \"label\": \"Description\",\n \"value\": \"Description\"\n },\n {\n \"label\": \"WriteMask\",\n \"value\": \"WriteMask\"\n },\n {\n \"label\": \"UserWriteMask\",\n \"value\": \"UserWriteMask\"\n },\n {\n \"label\": \"IsAbstract\",\n \"value\": \"IsAbstract\"\n },\n {\n \"label\": \"Symmetric\",\n \"value\": \"Symmetric\"\n },\n {\n \"label\": \"InverseName\",\n \"value\": \"InverseName\"\n },\n {\n \"label\": \"ContainsNoLoops\",\n \"value\": \"ContainsNoLoops\"\n },\n {\n \"label\": \"EventNotifier\",\n \"value\": \"EventNotifier\"\n },\n {\n \"label\": \"Value\",\n \"value\": \"Value\"\n },\n {\n \"label\": \"DataType\",\n \"value\": \"DataType\"\n },\n {\n \"label\": \"ValueRank\",\n \"value\": \"ValueRank\"\n },\n {\n \"label\": \"ArrayDimensions\",\n \"value\": \"ArrayDimensions\"\n },\n {\n \"label\": \"AccessLevel\",\n \"value\": \"AccessLevel\"\n },\n {\n \"label\": \"UserAccessLevel\",\n \"value\": \"UserAccessLevel\"\n },\n {\n \"label\": \"MinimumSamplingInterval\",\n \"value\": \"MinimumSamplingInterval\"\n },\n {\n \"label\": \"Historizing\",\n \"value\": \"Historizing\"\n },\n {\n \"label\": \"Executable\",\n \"value\": \"Executable\"\n },\n {\n \"label\": \"UserExecutable\",\n \"value\": \"UserExecutable\"\n }\n ],\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"1000\",\n \"description\": \"listen.sampling.interval\",\n \"id\": \"listen.sampling.interval\",\n \"isRequired\": true,\n \"name\": \"listen.sampling.interval\",\n \"type\": \"DOUBLE\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"10\",\n \"description\": \"listen.queue.size\",\n \"id\": \"listen.queue.size\",\n \"isRequired\": true,\n \"name\": \"listen.queue.size\",\n \"type\": \"LONG\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"true\",\n \"description\": \"listen.discard.oldest\",\n \"id\": \"listen.discard.oldest\",\n \"isRequired\": true,\n \"name\": \"listen.discard.oldest\",\n \"type\": \"BOOLEAN\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"false\",\n \"description\": \"listen.subscribe.to.children\",\n \"id\": \"listen.subscribe.to.children\",\n \"isRequired\": true,\n \"name\": \"listen.subscribe.to.children\",\n \"type\": \"BOOLEAN\"\n }\n ],\n \"factoryPid\": \"org.eclipse.kura.driver.opcua\",\n \"pid\": \"opcuaDriver\"\n }\n ],\n \"driverOCDs\": [\n {\n \"definition\": {\n \"ad\": [\n {\n \"cardinality\": 0,\n \"defaultValue\": \"default-server\",\n \"description\": \"OPC-UA Endpoint IP Address\",\n \"id\": \"endpoint.ip\",\n \"isRequired\": true,\n \"name\": \"Endpoint IP\",\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"53530\",\n \"description\": \"OPC-UA Endpoint Port\",\n \"id\": \"endpoint.port\",\n \"isRequired\": true,\n \"min\": \"1\",\n \"name\": \"Endpoint port\",\n \"type\": \"INTEGER\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"OPC-UA-Server\",\n \"description\": \"OPC-UA Server Name\",\n \"id\": \"server.name\",\n \"isRequired\": false,\n \"name\": \"Server Name\",\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"false\",\n \"description\": \"If set to true the driver will use the hostname, port, and server name parameters specified in the configuration instead of the values contained in endpoint descriptions fetched from the server.\",\n \"id\": \"force.endpoint.url\",\n \"isRequired\": false,\n \"name\": \"Force endpoint URL\",\n \"type\": \"BOOLEAN\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"120\",\n \"description\": \"Session timeout (in seconds)\",\n \"id\": \"session.timeout\",\n \"isRequired\": true,\n \"name\": \"Session timeout\",\n \"type\": \"INTEGER\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"60\",\n \"description\": \"Request timeout (in seconds)\",\n \"id\": \"request.timeout\",\n \"isRequired\": true,\n \"name\": \"Request timeout\",\n \"type\": \"INTEGER\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"40\",\n \"description\": \"The time to wait for the server response to the 'Hello' message (in seconds)\",\n \"id\": \"acknowledge.timeout\",\n \"isRequired\": true,\n \"name\": \"Acknowledge timeout\",\n \"type\": \"INTEGER\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"opc-ua client\",\n \"description\": \"OPC-UA application name\",\n \"id\": \"application.name\",\n \"isRequired\": true,\n \"name\": \"Application name\",\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"urn:kura:opcua:client\",\n \"description\": \"OPC-UA application uri\",\n \"id\": \"application.uri\",\n \"isRequired\": true,\n \"name\": \"Application URI\",\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"1000\",\n \"description\": \"The publish interval in milliseconds for the subscription created by the driver.\",\n \"id\": \"subscription.publish.interval\",\n \"isRequired\": true,\n \"name\": \"Subscription publish interval\",\n \"type\": \"LONG\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"PFX or JKS Keystore\",\n \"description\": \"Absolute path of the PKCS or JKS keystore that contains the OPC-UA client certificate, private key and trusted server certificates\",\n \"id\": \"certificate.location\",\n \"isRequired\": true,\n \"name\": \"Keystore path\",\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"0\",\n \"description\": \"Security Policy\",\n \"id\": \"security.policy\",\n \"isRequired\": true,\n \"name\": \"Security policy\",\n \"option\": [\n {\n \"label\": \"None\",\n \"value\": \"0\"\n },\n {\n \"label\": \"Basic128Rsa15\",\n \"value\": \"1\"\n },\n {\n \"label\": \"Basic256\",\n \"value\": \"2\"\n },\n {\n \"label\": \"Basic256Sha256\",\n \"value\": \"3\"\n }\n ],\n \"type\": \"INTEGER\"\n },\n {\n \"cardinality\": 0,\n \"description\": \"OPC-UA server username\",\n \"id\": \"username\",\n \"isRequired\": false,\n \"name\": \"Username\",\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"description\": \"OPC-UA server password\",\n \"id\": \"password\",\n \"isRequired\": false,\n \"name\": \"Password\",\n \"type\": \"PASSWORD\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"client-ai\",\n \"description\": \"Alias for the client certificate in the keystore\",\n \"id\": \"keystore.client.alias\",\n \"isRequired\": true,\n \"name\": \"Client certificate alias\",\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"false\",\n \"description\": \"Specifies whether to enable or not server certificate verification\",\n \"id\": \"authenticate.server\",\n \"isRequired\": true,\n \"name\": \"Enable server authentication\",\n \"type\": \"BOOLEAN\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"PKCS12\",\n \"description\": \"Keystore type\",\n \"id\": \"keystore.type\",\n \"isRequired\": true,\n \"name\": \"Keystore type\",\n \"option\": [\n {\n \"label\": \"PKCS11\",\n \"value\": \"PKCS11\"\n },\n {\n \"label\": \"PKCS12\",\n \"value\": \"PKCS12\"\n },\n {\n \"label\": \"JKS\",\n \"value\": \"JKS\"\n }\n ],\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"password\",\n \"description\": \"Configurable Property to set keystore password (default set to password)\",\n \"id\": \"keystore.password\",\n \"isRequired\": true,\n \"name\": \"Keystore password\",\n \"type\": \"PASSWORD\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"200\",\n \"description\": \"Maximum number of items that will be included in a single request to the server.\",\n \"id\": \"max.request.items\",\n \"isRequired\": true,\n \"name\": \"Max request items\",\n \"type\": \"INTEGER\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"BROWSE_PATH\",\n \"description\": \"The format to be used for channel name for subtree subscriptions. If set to BROWSE_PATH, the channel name will contain the browse path of the source node relative to the subscription root. If set to NODE_ID, the name will contain the node id of the source node.\",\n \"id\": \"subtree.subscription.name.format\",\n \"isRequired\": true,\n \"name\": \"Subtree subscription events channel name format\",\n \"option\": [\n {\n \"label\": \"BROWSE_PATH\",\n \"value\": \"BROWSE_PATH\"\n },\n {\n \"label\": \"NODE_ID\",\n \"value\": \"NODE_ID\"\n }\n ],\n \"type\": \"STRING\"\n }\n ],\n \"description\": \"OPC-UA Driver\",\n \"id\": \"org.eclipse.kura.driver.opcua\",\n \"name\": \"OpcUaDriver\"\n },\n \"pid\": \"org.eclipse.kura.driver.opcua\"\n }\n ],\n \"wireComponentDefinitions\": [\n {\n \"componentOCD\": [\n {\n \"cardinality\": 0,\n \"defaultValue\": \"records[0].TIMER !== null && records[0].TIMER.getValue() > 10 && records[0]['TIMER'].getValue() < 30;\\n\",\n \"description\": \"The boolean expression to be evaluated by this component when a wire envelope is received.\",\n \"id\": \"condition\",\n \"isRequired\": true,\n \"name\": \"condition\",\n \"type\": \"STRING\"\n }\n ],\n \"defaultInputPorts\": 1,\n \"defaultOutputPorts\": 2,\n \"factoryPid\": \"org.eclipse.kura.wire.Conditional\",\n \"inputPortNames\": {\n \"0\": \"if\"\n },\n \"maxInputPorts\": 1,\n \"maxOutputPorts\": 2,\n \"minInputPorts\": 1,\n \"minOutputPorts\": 2,\n \"outputPortNames\": {\n \"0\": \"then\",\n \"1\": \"else\"\n }\n }\n ]\n}\n
"},{"location":"kura-wires/wire-service-rest-v1/#wire-graph-snapshot-example","title":"Wire Graph snapshot example","text":"{\n \"configs\": [\n {\n \"pid\": \"org.eclipse.kura.wire.graph.WireGraphService\",\n \"properties\": {\n \"WireGraph\": {\n \"type\": \"STRING\",\n \"value\": \"{\\\"components\\\":[{\\\"pid\\\":\\\"timer\\\",\\\"inputPortCount\\\":0,\\\"outputPortCount\\\":1,\\\"renderingProperties\\\":{\\\"position\\\":{\\\"x\\\":-300,\\\"y\\\":-20},\\\"inputPortNames\\\":{},\\\"outputPortNames\\\":{}}},{\\\"pid\\\":\\\"logger\\\",\\\"inputPortCount\\\":1,\\\"outputPortCount\\\":0,\\\"renderingProperties\\\":{\\\"position\\\":{\\\"x\\\":-100,\\\"y\\\":-20},\\\"inputPortNames\\\":{},\\\"outputPortNames\\\":{}}}],\\\"wires\\\":[{\\\"emitter\\\":\\\"timer\\\",\\\"emitterPort\\\":0,\\\"receiver\\\":\\\"logger\\\",\\\"receiverPort\\\":0}]}\"\n }\n }\n },\n {\n \"pid\": \"timer\",\n \"properties\": {\n \"componentDescription\": {\n \"type\": \"STRING\",\n \"value\": \"A wire component that fires a ticking event on every configured interval\"\n },\n \"componentId\": {\n \"type\": \"STRING\",\n \"value\": \"timer\"\n },\n \"componentName\": {\n \"type\": \"STRING\",\n \"value\": \"Timer\"\n },\n \"cron.interval\": {\n \"type\": \"STRING\",\n \"value\": \"0/10 * * * * ?\"\n },\n \"emitter.port.count\": {\n \"type\": \"INTEGER\",\n \"value\": 1\n },\n \"factoryComponent\": {\n \"type\": \"BOOLEAN\",\n \"value\": false\n },\n \"factoryPid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.wire.Timer\"\n },\n \"kura.service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"timer\"\n },\n \"receiver.port.count\": {\n \"type\": \"INTEGER\",\n \"value\": 0\n },\n \"service.factoryPid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.wire.Timer\"\n },\n \"service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.wire.Timer-1642493602000-13\"\n },\n \"simple.custom.first.tick.interval\": {\n \"type\": \"INTEGER\",\n \"value\": 0\n },\n \"simple.first.tick.policy\": {\n \"type\": \"STRING\",\n \"value\": \"DEFAULT\"\n },\n \"simple.interval\": {\n \"type\": \"INTEGER\",\n \"value\": 10\n },\n \"simple.time.unit\": {\n \"type\": \"STRING\",\n \"value\": \"SECONDS\"\n },\n \"type\": {\n \"type\": \"STRING\",\n \"value\": \"SIMPLE\"\n }\n }\n },\n {\n \"pid\": \"logger\",\n \"properties\": {\n \"componentDescription\": {\n \"type\": \"STRING\",\n \"value\": \"A wire component which logs data as received from upstream connected Wire Components\"\n },\n \"componentId\": {\n \"type\": \"STRING\",\n \"value\": \"logger\"\n },\n \"componentName\": {\n \"type\": \"STRING\",\n \"value\": \"Logger\"\n },\n \"emitter.port.count\": {\n \"type\": \"INTEGER\",\n \"value\": 0\n },\n \"factoryComponent\": {\n \"type\": \"BOOLEAN\",\n \"value\": false\n },\n \"factoryPid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.wire.Logger\"\n },\n \"kura.service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"logger\"\n },\n \"log.verbosity\": {\n \"type\": \"STRING\",\n \"value\": \"QUIET\"\n },\n \"receiver.port.count\": {\n \"type\": \"INTEGER\",\n \"value\": 1\n },\n \"service.factoryPid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.wire.Logger\"\n },\n \"service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.wire.Logger-1642493602046-14\"\n }\n }\n }\n ]\n}\n
"},{"location":"kura-wires/wires-mqtt-namespace/","title":"Wires MQTT Namespace","text":"The CloudPublisher is a WireComponent that converts a WireEnvelope in a KuraPayload and publishes it over MQTT. Each WireRecord in a WireEnvelope is trivially converted to a KuraPayload and published on a configurable semantic data or control topic. During this process, the emitter PID of the WireEnvelope is discarded.
The CloudPublisher is agnostic with respect to the contents of the WireEnvelope. It does not know for example if a WireEnvelope contains data readings emitted from a WireAsset. On the other hand, WireAssetS are first-class citizens of a Wire graph and the source of the information which is processed by the downstream Wire components. Eventually, the WireEnvelope representing the output of the processing is connected to a CloudPublisher and published to a Cloud platform.
In the simplest case, a WireAsset is directly connected to a CloudPublisher and it would be useful to publish the telemetry data under a well-known topic namespace, for example the following full topic:
<accountName>/<deviceID>/W1/A1/<assetName>\n
In this case ${assetName} matches the emitterPID of the WireEnvelope emitted by the WireAsset and received by a CloudPublisher.
Interested applications can then subscribe to (or query a message datastore for):
<accountName>/<deviceID>/W1/#
for all Wires (W) topics<accountName>/<deviceID>/W1/A1/#
for all WireAsset (W/A) topics<accountName>/<deviceID>/W1/A1/<assetName>
for all topics for a specific WireAssetIn a more complex scenario there might be filters between the WireAsset \u201csource\u201d and the CloudPublisher \u201csink\u201d and the emitterPID of the WireEnvelope received by the publisher no longer matches the emitterPID of the WireEnvelope emitted by the WireAsset. However the published data still represents \u201cAsset\u201d (filtered) data and should be published under the topic above.
The Kura Wires model haven\u2019t the notion of source of an WireEnvelope since a given WireEnvelope instance does not move across the graph but only from one WireEmitter to downstream WireReceiverS that are free to emit something semantically different.
To overcome this issue:
W1/A1/$assetName
where tokens prefixed with $
will be expanded to the value of a property with the same name in a WireEnvelope\u2019s WireRecord.assetName
property to the WireEnvelope\u2019s WireRecord.The Join Component is a Multiport-enabled component that merges into a single Wire Envelope the properties contained in the envelopes received in the input ports. It is provided by default in every Kura installation.
In the image above a simple usage example of the Join component: two timers simulate separate paths in the graph and the envelopes received by the Conditional component are then merged into a single Wire Envelope that is then received by the logger component.
The behaviour of the Join component is specified by the barrier property.
"},{"location":"kura-wires/multiport-wire-components/mathematical-components-example/","title":"Mathematical Components Example","text":"Mathematical Wire components can be installed from the Eclipse Marketplace. For these examples, the Wire Math Multiport Components DP will be used, but other more specific operators can be found on the marketplace (like trigonometric functions).
The following Multiport-enabled Mathematical examples are provided:
In order to allow a better routing of data through the Wire Graph, Kura introduces a new class of Wire components named Multiport Wire Components.
With the addition of this new functionality, a compatible component instance can be defined with an arbitrary number of input and output ports.
In the example provided, we have two components in the Wire Composer:
Those components are available in every default installation of Kura.
In order to show the potentialities of the new APIs, in the Eclipse Kura Marketplace and in the Kura downloads page, are available few more multiport-enabled components for Mathematical processing.
"},{"location":"kura-wires/multiport-wire-components/multiport-wire-components/#convert-a-component-to-a-multiport-component","title":"Convert a Component to a Multiport Component","text":""},{"location":"kura-wires/multiport-wire-components/multiport-wire-components/#component-configuration-changes","title":"Component Configuration Changes","text":"The following properties need to be specified in the component configuration:
The component should also provide service interface org.eclipse.kura.wire.WireComponent
"},{"location":"kura-wires/multiport-wire-components/multiport-wire-components/#code-changes","title":"Code Changes","text":"To leverage all the new Multiport functionalities, a Multiport-enabled component must use the newly introduced MultiportWireSupport APIs that provide support to get the list of Emitter and Receiver Ports, as well as to create a new Wire Envelope from a list of Wire Records.
For the conditional component, that has two output ports, the following code allows to get the proper Wire Support from the Wire Helper Service and to get the then and else ports to be used to push the processed envelopes.
this.wireSupport = (MultiportWireSupport) this.wireHelperService.newWireSupport(this);\n final List<EmitterPort> emitterPorts = this.wireSupport.getEmitterPorts();\n this.thenPort = emitterPorts.get(0);\n this.elsePort = emitterPorts.get(1);\n
To emit the result, the code has to be adapted to use the Wire Support to create the Wire Envelope that has to be sent. Effectively, the envelope is sent to the corresponding wire invoking the emit method of the corresponding Port, as shown below.
final WireEnvelope outputEnvelope = this.wireSupport.createWireEnvelope(inputRecords);\n\nif ((Boolean) decision) {\n this.thenPort.emit(outputEnvelope);\n} else {\n this.elsePort.emit(outputEnvelope);\n}\n
"},{"location":"kura-wires/script-components/graalvm-conditional-component/","title":"GraalVM\u2122 Conditional Component","text":"The Conditional Component is a multiport-enabled component that implements the if-then-else logic in the Wire Composer.
In the image above a simple usage example of the conditional component: a timer ticks and the envelope is received by the conditional component. If the timer has an even number of seconds, then it will evaluate to true
and forward the received envelope to the then port: the 'verbose' logger will receive the input.
The choice between the two ports is performed based on a condition expressed in the component configuration as in the image below.
"},{"location":"kura-wires/script-components/graalvm-filter-component/","title":"GraalVM\u2122 Filter Component","text":"The Filter Component provides scripting functionalities in Kura Wires using the GraalVM\u2122 JavaScript engine:
The following global variables are available to the script:
input
: an object that represents the received wire envelope.output
: an object that allows to emit wire records.logger
: a slf4j logger.The following utility functions are available (see Creating and emitting wire records for usage):
newWireRecord(Map<String, TypedValue<?>) -> WireRecord
newByteArray(int) -> byte[]
newBooleanValue(boolean) -> TypedValue
newByteArrayValue(byte[]) -> TypedValue
newDoubleValue(number) -> TypedValue
newIntegerValue(number) -> TypedValue
newLongValue(number) -> TypedValue
newStringValue(object) -> TypedValue
The following global constants expose the org.eclipse.kura.type.DataType
enum variants:
BOOLEAN
BYTE_ARRAY
DOUBLE
FLOAT
INTEGER
LONG
STRING
The received envelope is represented by the input global variable and is mapped in Javascript as a WireEnvelope
object.
GraalVM Javascript Engine allows a 1:1 mapping of Java Objects to JavaScript ones. Hence, it is possible to access the WireRecord
s of the envelope and the emitter pid using the methods specified in the WireEnvelope
Kura API:
logger.info('Emitter pid is {}', input.getEmitterPid())\nvar records = input.getRecords()\n
The records
array can be iterated to extract the WireRecord
properties (reference the WireRecord
Kura API):
for(let i=0; i<records.length; i++) {\n // WireRecord.getProperties() returns a map of String - TypedValue\n for (const [keyString, typedValue] of records[i].getProperties()) {\n logger.info('The {}-th record contains:'\\, String(i))\n logger.info('{}={}\\n', keyString, typedValue.getValue())\n }\n}\n
As in the example above, wireRecord.getProperties
returns a map of String, TypedValue
. Refer to the TypedValue
Kura API for the accessible public methods list.
New mutable WireRecord
instances can be created using the newWireRecord(Map<String, TypedValue<?>)
function. The properties of a mutable WireRecord
can be modified by setting Javascript object properties. The properties of a WireRecord
object must be instances of the TypedValue
class created using the new<type>Value()
family of functions. Setting different kind of objects as properties of a WireRecord
will result in an exception.
The output global variable is an object that can be used for emitting WireRecord
s. This object contains a list of WireRecord
s that will be emitted when the script execution finishes if no exceptions are thrown. The following code is an example of how to emit a list containing a single WireRecord
:
var output = new Array()\nvar outputMap = new Object()\n\nvar byteArray = newByteArray(4)\nbyteArray[0] = 1\nbyteArray[1] = 2\nbyteArray[2] = 0xaa\nbyteArray[3] = 0xbb\n\noutputMap['example.integer'] = newIntegerValue(10)\noutputMap['example.long'] = newLongValue(100)\noutputMap['example.float'] = newFloatValue(1.014)\noutputMap['example.double'] = newDoubleValue(10.12)\noutputMap['example.boolean'] = newBooleanValue(true)\noutputMap['example.string'] = newStringValue('Hello World!')\noutputMap['example.byte.array'] = newByteArrayValue(byteArray)\n\noutput[0] = newWireRecord(outputMap)\n
"},{"location":"kura-wires/script-components/graalvm-filter-component/#script-context","title":"Script context","text":"The script.context.drop option allows to reset the script context. If set to true
the script context will be dropped every time the component configuration is updated, resetting the value of any persisted variable.
In the example below, with script.context.drop=false the following script will preserve the value of counter
across executions. Setting script.context.drop=true will cause counter
to be undefined
every time the component is triggered.
counter = typeof(counter) === 'undefined'\n ? 0 // counter is undefined, initialise it to zero\n : counter; // counter is already defined, keep the previous value\n
"},{"location":"kura-wires/script-components/introduction/","title":"Introduction to the Script Components","text":"The Script Components allow for performing more complex operations on the received Wire Envelopes using a JavaScript Engine.
Depending if the target device is running on Java 8 or Java 17, there are several components to choose from.
For devices running a JRE with Nashorn JS Engine (Java < 15), a Script Filter and a Conditional Component are provided:
The above components will run only on Java < 15 since the Nashorn dependency is not included in the DP. The two components are available in the Eclipse Marketplace as two separate entries. These components are deprecated as of Kura version 5.3.
The following components instead have the GraalVM\u2122 JavaScript Engine included in the DP and therefore do not require a JRE with Nashorn JS Engine:
The input scripts for these components are not compatible with the Nashorn implementations Script Filter and Conditional Component. Both components are shipped as a single DP named org.eclipse.kura.wire.script.tools. Since the JS engine dependency is shipped along with the DP, these components will work on both Java 8 and Java 17 devices but the DP is bigger in size (~18,6 MB).
"},{"location":"kura-wires/script-components/nashorn-conditional-component/","title":"Nashorn Conditional Component","text":"Warning
This component is deprecated as of Kura version 5.3 since no more available on Java 17.
The Conditional component is a multiport-enabled component that implements the if-then-else logic in the Wire Composer. It is provided by default in every Kura installation.
In the image above a simple usage example of the Conditional component: a timer ticks and the envelope is received by the Conditional component. The message is then processed and can be sent downstream to the logger component (then port) or to a publisher (else port).
The choice between the two ports is performed based on a condition expressed in the Conditional component configuration.
"},{"location":"kura-wires/script-components/nashorn-script-filter/","title":"Nashorn Script Filter","text":"Warning
This component is deprecated as of Kura version 5.3 since no more available on Java 17.
The Script Filter Component provides scripting functionalities in Kura Wires using the Nashorn Javascript engine:
The following global variables are available to the script:
input
: an object that represents the received wire envelope.output
: an object that allows to emit wire records.logger
: a slf4j loggerThe following utility functions are available (see Creating and emitting wire records for usage):
newWireRecord(void) -> WireRecordWrapper
newByteArray(void) -> byte[]
newBooleanValue(boolean) -> TypedValue
newByteArrayValue(byte[])
-> TypedValue
newDoubleValue(number) -> TypedValue
newFloatValue(number) -> TypedValue
newIntegerValue(number) -> TypedValue
newLongValue(number) -> TypedValue
newStringValue(object) -> TypedValue
The following global constants expose the org.eclipse.kura.type.DataType
enum variants:
BOOLEAN
BYTE_ARRAY
DOUBLE
FLOAT
INTEGER
LONG
STRING
The received envelope is represented by the input global variable and it has the following properties:
Each element of the records array is an immutable object that represents a received wire record. Wire record properties are directly mapped to Javascript object properties, and are instances of the org.eclipse.kura.type.TypedValue
class. Each Wire Record property has the following methods available:
getType(void) -> DataType
: Returns the type of the value, as a DataType enum variant. Can be matched against the data type constants described above.getValue(void) -> Object
: Returns the actual value.The javascript objects referred as WireRecords in this guide are not instances of the org.eclipse.kura.wire.WireRecord
class, but are wrappers that map WireRecord properties into javascript properties. The following code is a simple example script that show how to use the filter:
// get the first record from the envelope\nvar record = input.records[0]\n// let's assume it contains the LED boolean property and the TEMPERATURE double property\nrecord.LED1.getType() === BOOLEAN // evaluates to true\nif (record.LED1.getValue()) {\n // LED1 is on\n}\nrecord.LED1.getType() === DOUBLE // evaluates to true\nif (record.TEMPERATURE.getValue() > 50) {\n // temperature is high, do something\n}\n
"},{"location":"kura-wires/script-components/nashorn-script-filter/#creating-and-emitting-wire-records","title":"Creating and emitting wire records","text":"New mutable WireRecord
instances can be created using the newWireRecord(void) -> WireRecordWrapper
function. The properties of a mutable WireRecord
can be modified by setting Javascript object properties. The properties of a WireRecord
object must be instances of the TypedValue
class created using the new<type>Value()
family of functions. Setting different kind of objects as properties of a WireRecord
will result in an exception.
The output global variable is an object that can be used for emitting WireRecords. This object contains a list of WireRecords that will be emitted when the script execution finishes, if no exceptions are thrown. New records can be added to the list using the add(WireRecordWrapper)
function. It is also possible to emit records contained in the received WireEnvelope.
The script filter will emit a wire envelope only if the WireRecord list is not empty when the script execution completes. The following code is an example about how to emit a value:
var record = newWireRecord()\n\nvar byteArray = newByteArray()\nbyteArray[0] = 1\nbyteArray[1] = 2\nbyteArray[2] = 0xaa\nbyteArray[3] = 0xbb\n\nrecord.LED1 = newBooleanValue(true)\nrecord.foo = newStringValue('bar')\nrecord['myprop'] = newDoubleValue(123.456)\nrecord['example.long'] = newLongValue(100)\nrecord['example.float'] = newFloatValue(1.014)\nrecord['example.byte.array'] = newByteArrayValue(byteArray)\n\noutput.add(record)\n
"},{"location":"kura-wires/script-components/nashorn-script-filter/#script-context","title":"Script context","text":"The script.context.drop option allows to reset the script context. If set to true
the script context will be dropped every time the component configuration is updated, resetting the value of any persisted variable.
In the example below, with script.context.drop=false the following script will preserve the value of counter
across executions. Setting script.context.drop=true will cause counter
to be undefined
every time the component is triggered.
counter = typeof(counter) === 'undefined'\n ? 0 // counter is undefined, initialise it to zero\n : counter; // counter is already defined, keep the previous value\n
"},{"location":"kura-wires/single-port-wire-components/ai-wire-component/","title":"AI Wire Component","text":"The component allows interacting with an InferenceEngineService
to perform machine learning-related operations. For boards that are not explicitly made for AI, the component can be installed from the Eclipse Marketplace at this link.
An InferenceEngineService is a Kura service that implements a simple API to interface with an Inference Engine. The Inference Engine allows to perform inference on trained Artificial Intelligence models commonly described by a file and some configuration for explaining its input and outputs. An example of Inference Engine implementation is the Nvidia\u2122 Triton Server inference engine.
In a normal machine learning flow, the input is preprocessed before it is given to the machine learning algorithm, and the result is processed again to be adapted to the rest of the pipeline.
Once these models are loaded in the engine, the AI wire component allows to specify the name of the models that are used in the pre-processing, infer, and post-processing steps. Only the infer model name is mandatory so that it is possible to just use the strictly necessary steps in case the pre/post-processing is performed directly by the infer step.
"},{"location":"kura-wires/single-port-wire-components/ai-wire-component/#models-input-and-output-formats","title":"Models Input and Output formats","text":"The AI wire component takes a WireEnvelope
as an input, it processes its records and feeds them to the specified preprocessing or inference model. The outputs of the inference or the post-processing step are then reconverted into a wire record. This section explains the inputs and output formats that the wire component is expecting. Not specifying the models according to this contract will result in a non-functioning inference.
The 3 inference steps are applied on each WireRecord
contained in the input WireEnvelope
.
The inputs and outputs will have assigned the corresponding Kura DataType
, which can be one of:
BOOLEAN
DOUBLE
FLOAT
INTEGER
LONG
STRING
BYTE_ARRAY
Reference to Introduction for the data types that are allowed to flow through the wires.
The models that manage the input and the output must expect a list of inputs such that:
WireRecord
properties[1]
In the following, two example configurations for Triton Inference Engine models are provided. A complete usage example that implements an Anomaly Detector using a RaspberryPi SenseHat is provided in the Kura examples repository.
"},{"location":"kura-wires/single-port-wire-components/ai-wire-component/#input-specification-example","title":"Input Specification Example","text":"Following, an example of a model configuration for the Nvidia\u2122 Triton Inference Engine. It expects the input from the WireEnvelope
that contains a record with properties:
ACCELERATION
of type Float
CHANNEL_0
of type Integer
STREAM
of type byte[]
GYRO
of type Boolean
This record can be generated from an asset with channel names as above. The output will be a single tensor of type Float
, of shape 1x13, and name OUT_PRE
.
Note that each input will have shape 1.
name: \"preprocessor\"\nbackend: \"python\"\n\ninput [\n {\n name: \"ACCELERATION\"\n data_type: FP32\n dims: [ 1 ]\n }\n]\ninput [\n {\n name: \"CHANNEL_0\"\n data_type: INT32\n dims: [ 1 ]\n }\n]\ninput [\n {\n name: \"STREAM\"\n data_type: BYTES\n dims: [ 1 ]\n }\n]\ninput [\n {\n name: \"GYRO\"\n data_type: BOOL\n dims: [ 1 ]\n }\n]\noutput [\n {\n name: \"OUT_PRE\"\n data_type: FP32\n dims: [ 13 ]\n }\n]\ninstance_group [{ kind: KIND_CPU }]\n
"},{"location":"kura-wires/single-port-wire-components/ai-wire-component/#output-specification-example","title":"Output Specification Example","text":"Following, an example of a Nvidia\u2122 Triton Inference Engine configuration that takes input IN_POST
and produces outputs that will be mapped to a WireRecord
with the properties as follows: - RESULT0
of type Boolean
- RESULT1
of type Integer
- RESULT2
of type byte[]
- RESULT3
of type Float
Note that each output will have shape 1.
name: \"postprocessor\"\nbackend: \"python\"\n\ninput [\n {\n name: \"IN_POST\"\n data_type: FP32\n dims: [ 1, 5 ]\n }\n]\noutput [\n {\n name: \"RESULT0\"\n data_type: BOOL\n dims: [ 1 ]\n }\n]\noutput [\n {\n name: \"RESULT1\"\n data_type: INT32\n dims: [ 1 ]\n }\n]\noutput [\n {\n name: \"RESULT2\"\n data_type: BYTES\n dims: [ 1 ]\n }\n]\noutput [\n {\n name: \"RESULT3\"\n data_type: FP32\n dims: [ 1 ]\n }\n]\ninstance_group [{ kind: KIND_CPU }]\n
"},{"location":"kura-wires/single-port-wire-components/db-store-and-filter/","title":"Wire Record Store and Wire Record Query","text":"This tutorial will present how to use Wire Record Store and Wire Record Query components and provide an example based on the OPC-UA simulated server already used in OPC-UA Application.
The Wire Record Store component allows the wire graphs to interact with a persistend Wire Record store implementation, for example a SQL database. It stores in a user-defined collection all the envelopes received by the component.
The Wire Record Query component, instead, can run a custom query on the attached store and emit the result on the wire.
Note
The Wire Record Store and Wire Record Query components have been introduced in Kura 5.3.0 as a replacement of the Db Store and Db Filter, that have been deprecated.
The reason of the deprecation is the fact that Db Store and Db Filter only support databases that provide a JDBC interface. Moreover, the old Db Store interacts with the database using a set of hardcoded SQL queries. This fact makes it difficult to use it with different databases since the syntax of the queries is usually database-specific.
The new components use the org.eclipse.kura.wire.store.provider.WireRecordStoreProvider
and org.eclipse.kura.wire.store.provider.QueryableWireRecordStoreProvider
APIs introduced in 5.3.0 allowing to use them with generic data store implementations.
Please note that Wire Record Query component is not portable by nature, since it allows to execute an arbitrary user defined query. The new APIs allows to use it with non-JDBC data stores.
The Wire Record Store component can be configured as follows:
The Wire Record Query component can be configured as follows:
The following procedure will create a wire graph that collects data from a simulated OPC-UA Server, stores it in a table in the database, using the Wire Record Store component, and publishes it in the cloud platform. Moreover, the Wire Record Query component is used to read from the database and write data to the OPC-UA Server based on the values read.
"},{"location":"kura-wires/single-port-wire-components/db-store-and-filter/#configure-opc-ua-server-simulator","title":"Configure OPC-UA server simulator","text":"Configure the new service as follows:
Click on Wires under System
Configure the new OPC-UA asset, adding new Channels as shown in the following image. Make sure that all the channels are set to READ.
Add a new Wire Record Store named DBStore component and configure it as follows:
Add another Asset with the OPC-UA Driver, configured as shown in the following image. Be sure that all the channels are set to WRITE.
Note
Be aware that the Query syntax can vary accordingly to the dialect used by the database. For example, the MySQL dialect doesn't allow to surround the table or columns names with double-quotes. In the H2DB, this is mandatory instead.
Connect the components as shown in the following image, then click on \u201cApply\u201d and check the logs and the cloud platform that the data is correctly published.
This page describes the usage of the FIFO component in Wires.
The current Wires threading model allows any component to perform potentially blocking operations when a wire envelope is received.
The fact that the wire envelopes are delivered synchronously implies that if a wire component performs blocking operations, other components in the same subgraph might be blocked as well, introducing delays in the processing of the graph.
The FIFO component can be used for decoupling blocking or slow wire components from other parts of the graph that cannot tolerate delays.
In the graph above, the NODELAY component cannot tolerate potential delays introduced by the DB component, adding a FIFO component allows to decouple the two components.
This component implements a FIFO queue that operates as follows:
In this way, the threads running the upstream components are not affected by blocking operations performed by the downstream components.
In the example above there will be two threads that manage the processing of the graph:
A thread from the TIMER Quartz scheduler pool handles the processing for the NODELAY component and submits the envelopes produced by it to the queue of the FIFO component.
A second thread introduced by the FIFO component pops the received envelopes from the queue and dispatches them to the DB component, performing the processing required by it.
In this way, the NODELAY and DB components are decoupled because they are managed by different threads.
"},{"location":"kura-wires/single-port-wire-components/fifo-component/#configuration","title":"Configuration","text":"The FIFO component configuration is composed of the following properties:
queue.capacity: The size of the queue in terms of the number of storable wire envelopes.
discard.envelopes : Configures the behavior of the component in case of a full queue.
If set to true, envelopes received when the queue is full will be dropped. In this mode, submitting an envelope to the queue is always a non-blocking operation. It should be used if occasionally losing wire envelopes is acceptable for the application, but introducing delays for upstream components is not.
If set to false, adding an envelope when the queue is full will block the submitting thread until there is space in the queue. Submitting an envelope to the FIFO component can be a blocking operation if the queue is full. This mode should be used if dropping wire envelopes is unacceptable for upstream components.
The probability of dropping envelopes in discard.envelopes=true mode or the probability of blocking upstream components in discard.envelopes=false mode can be controlled by setting a proper queue size.
"},{"location":"kura-wires/usage-examples/eddystone-driver-application/","title":"Eddystone\u2122 Driver Application with RuuviTag+","text":"As presented in Eddystone Driver, Kura provides a specific driver that can be used to listen for Eddystone\u2122 beacons. The driver is available only for gateways that support the new Kura BLE APIs.
This tutorial will explain how to configure an Eddystone\u2122 driver and put it into a Wire graph that retrieves data from a RuuviTag+. For further information about RuuviTag see here.
"},{"location":"kura-wires/usage-examples/eddystone-driver-application/#configure-kura-wires-eddystone-application","title":"Configure Kura Wires Eddystone application","text":"Install the Eddystone\u2122 driver from the Eclipse Kura Marketplace.
On the Kura Web Interface, instantiate an Eddystone\u2122 Driver:
From the Drivers and Assets tab, add a new asset bound to the Eddystone\u2122 driver:
UID
type and the second for the URL
. In this example only the URL
will be used.Click on Wires under System.
Add a new Asset with the previously added Eddystone asset.
Add a new Javascript Filter component. The filter will be configured to parse the URL
frames coming from the RuuviTag+ and extract the environmental data from the on-board sensors. In the script window write the following code:
function toHexString(str) {\n var hex = '';\n for ( i = 0; i < str.length; i++ ) {\n var hexTemp = str.charCodeAt(i).toString(16)\n hex += (hexTemp.length==2?hexTemp:'0'+hexTemp);\n}\nreturn hex;\n};\n\nfunction decodeValues(rawSensors) {\n var rawSensorsDecoded = Base64.decode(rawSensors)\n logger.info(toHexString(rawSensorsDecoded))\n var sensorsValues = new Array();\n // Data Format Definition (4)\n var format = parseInt(rawSensorsDecoded[0].charCodeAt(0));\n if (format == 4) {\n sensorsValues.push(format)\n // Humidity\n sensorsValues.push(rawSensorsDecoded[1].charCodeAt(0) * 0.5)\n // Temperature\n sensorsValues.push(rawSensorsDecoded[2].charCodeAt(0) & 0x7f)\n // Pressure\n sensorsValues.push(parseInt(rawSensorsDecoded[4].charCodeAt(0) << 8 )+ parseInt(rawSensorsDecoded[5].charCodeAt(0) & 0xff) + 50000)\n // Random id of tag\n sensorsValues.push(rawSensorsDecoded[6].charCodeAt(0))\n }\n return sensorsValues;\n};\n\nload(\"https://gist.githubusercontent.com/jarus/948005/raw/524bea3b4e0b74c06c9cfd2a8e54429dda1918fe/base64.js\")\nvar record = input.records[0]\nif (record.URLEddystone != null) {\n var values = record.URLEddystone.getValue().split(\";\")\n\n if (values.length == 5 && values[1].split(\"#\").length == 2) {\n var outRecord = newWireRecord()\n var sensorsValues = decodeValues(values[1].split(\"#\")[1])\n if (sensorsValues.length == 5) {\n outRecord.format = newIntegerValue(sensorsValues[0])\n outRecord.humidity = newDoubleValue(sensorsValues[1])\n outRecord.temperature = newDoubleValue(sensorsValues[2])\n outRecord.pressure = newIntegerValue(sensorsValues[3])\n outRecord.id = newIntegerValue(sensorsValues[4])\n }\n outRecord.txPower = newIntegerValue(parseInt(values[2]))\n outRecord.rssi = newIntegerValue(parseInt(values[3]))\n outRecord.distance = newDoubleValue(parseFloat(values[4]))\n\n output.add(outRecord)\n }\n}\n
Add Logger component and set the log.verbosity to VERBOSE.
Connect the Asset to the Filter and this to the Logger.
Click on Apply and check on the logs that the environmental data are correctly logged.
INFO o.e.k.w.s.f.p.ScriptFilter - 04541a00c35078\nINFO o.e.k.i.w.l.Logger - Received WireEnvelope from org.eclipse.kura.wire.ScriptFilter-1537884418687-2\nINFO o.e.k.i.w.l.Logger - Record List content:\nINFO o.e.k.i.w.l.Logger - Record content:\nINFO o.e.k.i.w.l.Logger - txPower : -7\nINFO o.e.k.i.w.l.Logger - rssi : -55\nINFO o.e.k.i.w.l.Logger - distance : 251.18864315095797\nINFO o.e.k.i.w.l.Logger - format : 4\nINFO o.e.k.i.w.l.Logger - temperature : 26.0\nINFO o.e.k.i.w.l.Logger - humidity : 42.0\nINFO o.e.k.i.w.l.Logger - pressure : 100000\nINFO o.e.k.i.w.l.Logger - id : 120\nINFO o.e.k.i.w.l.Logger -\nINFO o.e.k.w.s.f.p.ScriptFilter - 04401a00c35078\nINFO o.e.k.i.w.l.Logger - Received WireEnvelope from org.eclipse.kura.wire.ScriptFilter-1537884418687-2\nINFO o.e.k.i.w.l.Logger - Record List content:\nINFO o.e.k.i.w.l.Logger - Record content:\nINFO o.e.k.i.w.l.Logger - txPower : -7\nINFO o.e.k.i.w.l.Logger - rssi : -39\nINFO o.e.k.i.w.l.Logger - distance : 39.810717055349734\nINFO o.e.k.i.w.l.Logger - format : 4\nINFO o.e.k.i.w.l.Logger - temperature : 26.0\nINFO o.e.k.i.w.l.Logger - humidity : 32.0\nINFO o.e.k.i.w.l.Logger - pressure : 100000\nINFO o.e.k.i.w.l.Logger - id : 120\nINFO o.e.k.i.w.l.Logger -\n
In this section a simple but effective example of the GPIO Driver on Wires will be presented. This example will implement a Wire graph that toggles a digital GPIO. A listener will be attached to an input GPIO externally connected to the first one.
Setup a Raspberry Pi as shown in GPIO Driver section. Add a cable from the LED contact near the red cable to pin 37 (gpio 26) on the RaspberryPi.
"},{"location":"kura-wires/usage-examples/gpio-driver-application/#configure-kura-wires-gpio-driver-application","title":"Configure Kura Wires GPIO Driver Application","text":"Install the GPIO Driver from the Eclipse Kura Marketplace.
On the Kura web interface, instantiate a GPIO Driver:
From the \"Drivers and Assets\" tab, add a new asset bound to the GPIO driver:
As in point 3., create a new asset as shown below:
Click on \"Wires\" under \"System\".
Add a new \"Timer\" component and configure the interval at which the LED will be toggled.
Add a new \"Script Filter\" (it can be downloaded from the Eclipse Marketplace and configure it with the following script:
// create a persistent counter\ncounter = typeof(counter) === 'undefined' ? 0 : counter\ncounter++\n\n// emit the counter value in a different WireRecord\nvar counterRecord = newWireRecord()\ncounterRecord.LED = newBooleanValue(counter%2==0)\noutput.add(counterRecord)\n
Add the \"Asset\" created at point 3 and connect the \"Timer\" to the \"Filter\" and the latter to the \"Asset\".
Add the \"Asset\" created at point 4.
Add \"Logger\" component and set log.verbosity to \"VERBOSE\".
Connect the latter \"Asset\" to the \"Logger\". The resulting Wire Graph should be as below:
Click on \"Apply\". After a while, the led on the breadboard should start to blink at a rate defined by the \"Timer\" as shown below:
Moreover, the kura.log file should show a long sequencce of messages reporting that the value from the input gpio is changed:
2018-04-09 13:08:42,990 [Thread-3289] INFO o.e.k.i.w.l.Logger - Received WireEnvelope from org.eclipse.kura.wire.WireAsset-1523276074484-23\n2018-04-09 13:08:42,991 [Thread-3289] INFO o.e.k.i.w.l.Logger - Record List content: \n2018-04-09 13:08:42,992 [Thread-3289] INFO o.e.k.i.w.l.Logger - Record content: \n2018-04-09 13:08:42,993 [Thread-3289] INFO o.e.k.i.w.l.Logger - LED_Feedback : false\n2018-04-09 13:08:42,993 [Thread-3289] INFO o.e.k.i.w.l.Logger - assetName : GPIOAssetFeedback\n2018-04-09 13:08:42,994 [Thread-3289] INFO o.e.k.i.w.l.Logger - LED_Feedback_timestamp : 1523279322990\n2018-04-09 13:08:42,994 [Thread-3289] INFO o.e.k.i.w.l.Logger - \n2018-04-09 13:08:44,988 [Thread-3291] INFO o.e.k.i.w.l.Logger - Received WireEnvelope from org.eclipse.kura.wire.WireAsset-1523276074484-23\n2018-04-09 13:08:44,989 [Thread-3291] INFO o.e.k.i.w.l.Logger - Record List content: \n2018-04-09 13:08:44,989 [Thread-3291] INFO o.e.k.i.w.l.Logger - Record content: \n2018-04-09 13:08:44,989 [Thread-3291] INFO o.e.k.i.w.l.Logger - LED_Feedback : true\n2018-04-09 13:08:44,989 [Thread-3291] INFO o.e.k.i.w.l.Logger - assetName : GPIOAssetFeedback\n2018-04-09 13:08:44,989 [Thread-3291] INFO o.e.k.i.w.l.Logger - LED_Feedback_timestamp : 1523279324988\n
As presented in the iBeacon\u2122 Driver, Kura provides a specific driver that can be used to listen for iBeacons packets. The driver is available only for gateways that support the new Kura BLE APIs.
This tutorial will explain how to configure a Wire graph that get iBeacon\u2122 data and show them to a logger.
"},{"location":"kura-wires/usage-examples/ibeacon-driver-application/#configure-the-wires-ibeacontm-application","title":"Configure the Wires iBeacon\u2122 Application","text":"Install the iBeacon driver from the Eclipse Kura Marketplace.
On the Web Interface, instantiate the iBeacon Driver:
From the \"Drivers and Assets\" tab, add a new asset binded to the iBeacon driver:
Click on the \"New Asset\" button and fill the form with the \"Asset Name\" and selecting the driver created in step 2. as \"Driver Name\". Click \"Apply\" and a new asset will be listed under the iBeacon driver.
Click on the new asset and configure it, adding a single channel that represents a listener for iBeacon\u2122 advertising packets. Check the listen checkbox for the channel.
Click on \"Wires\" under \"System\".
Add a new \"Asset\" with the previously added iBeacon asset.
Add a new \"Javascript Filter\" component. The filter will be configured to parse the iBeacon packets and extract relevant data from it. In the script window write the following code:
var record = input.records[0]\nif (record.ibeacon != null) {\n var values = record.ibeacon.getValue().split(\";\")\n\n if (values.length == 6) {\n var outRecord = newWireRecord()\n outRecord.uuid = newStringValue(values[0]) \n outRecord.txPower = newIntegerValue(parseInt(values[1]))\n outRecord.rssi = newIntegerValue(parseInt(values[2]))\n outRecord.major = newIntegerValue(parseInt(values[3]))\n outRecord.minor = newIntegerValue(parseInt(values[4]))\n outRecord.distance = newDoubleValue(parseFloat(values[5]))\n\n output.add(outRecord)\n }\n}\n
Add \"Logger\" component and set the log.verbosity to VERBOSE
Click on \"Apply\".
Using this graph, every iBeacon packet will be detected and reported to the log, as shown below. To simulate an iBeacon device, it is possible to use another gateway with the iBeacon advertiser example.
INFO o.e.k.i.w.l.Logger - Received WireEnvelope from org.eclipse.kura.wire.WireAsset-1537886139797-15\nINFO o.e.k.i.w.l.Logger - Record List content:\nINFO o.e.k.i.w.l.Logger - Record content:\nINFO o.e.k.i.w.l.Logger - assetName : iBeaconAsset\nINFO o.e.k.i.w.l.Logger - iBeacon : aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee;0;-38;0;0;79.43282347242814\nINFO o.e.k.i.w.l.Logger - iBeacon_timestamp : 1537886424085\nINFO o.e.k.i.w.l.Logger -\nINFO o.e.k.i.w.l.Logger - Received WireEnvelope from org.eclipse.kura.wire.WireAsset-1537886139797-15\nINFO o.e.k.i.w.l.Logger - Record List content:\nINFO o.e.k.i.w.l.Logger - Record content:\nINFO o.e.k.i.w.l.Logger - assetName : iBeaconAsset\nINFO o.e.k.i.w.l.Logger - iBeacon : aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee;0;-42;0;0;125.89254117941674\nINFO o.e.k.i.w.l.Logger - iBeacon_timestamp : 1537886425086\nINFO o.e.k.i.w.l.Logger -\n
This tutorial will describe how to collect data from an OPC-UA device and publish them on a cloud platform using Wires. The OPC-UA server device will be emulated using a bundle running on Kura.
"},{"location":"kura-wires/usage-examples/opcua-application/#configure-opc-ua-server-simulator","title":"Configure OPC-UA server simulator","text":"As presented in the Ti SensorTag Driver, Kura provides a specific driver that can be used to interact with Texas Instruments SensorTag devices. The driver is available only for gateways that support the new Bluetooth LE APIs.
This tutorial will explain how to configure a Wire graph that connects with a SensorTag, reads sensor values and publishes data to a cloud platform.
Warning
The SensorTag driver can be used only with TI SensorTags with firmware version >1.20. If your device has an older firmware, please update it.
"},{"location":"kura-wires/usage-examples/ti-sensortag-application/#configure-the-ti-sensortag-application","title":"Configure the TI SensorTag Application","text":"Install the TI SensorTag driver from the Eclipse Kura Marketplace
On the Kura Administrative Web Interface, instantiate a SensorTag Driver:
org.eclipse.kura.driver.ble.sensortag
as Driver Factory, type a name in Driver Name and click the Apply button: a new driver will be instantiated and listed in the page.In the Drivers and Assets tab add a new asset and associate it to the SensorTag driver:
Click Apply.
Apply the following configuration for the Asset instance:
Create a Wire Graph as in the following picture.
Please note that the driver supports also unsolicited inputs, setting up a notification for the given channel. In this case, it is sufficient to check the listen option for the chosen channel. The Timer is not needed because the SensorTag will automatically emit the values every notification.period milliseconds.
Kura QA activities focused on two main areas:
More on the unit and integration tests can be read in unit testing. More about manual system testing can be read in system testing.
"},{"location":"quality-assurance/system-testing/","title":"System Testing","text":""},{"location":"quality-assurance/system-testing/#qa-procedure","title":"QA Procedure","text":"A set of automated and manual test are performed before releasing a new Eclipse\u2122 Kura version to ensure software follows our quality standards.
Once a Release Candidate (RC) is tagged on its maintenance branch the QA process starts. The QA process involves a set of automated and manual tests performed on the target environment listed below. These tests are updated continuosly to follow the large amount of features added in each release. The QA process continues with new Release Candidate builds until the amount of defects in the software is reduced. When this happens the RC is promoted to final release and tagged on the maintenance branch.
"},{"location":"quality-assurance/system-testing/#environment","title":"Environment","text":""},{"location":"quality-assurance/system-testing/#hardware","title":"Hardware","text":"Build-time testing is further divided into unit testing and integration testing.
Unit testing is focused on testing separate methods or groups of methods, preferably in a single class. This way it can verify the correct operation of difficult-to-reach corner cases.
Integration testing is a more-high-level testing that tests certain functionality on a group of connected services in an approximation of the real environment. It verifies that the services can successfully register in the environment and connect to other services as well as perform their tasks.
Code coverage of the develop branch can be observed in Jenkins.
For some tips on running the tests also check Kura GitHub Wiki.
"},{"location":"quality-assurance/unit-testing/#unit-testing_1","title":"Unit Testing","text":"Unit tests should try to cover as many corner cases in the code as possible. Add them for (all) the new code you decide to contribute.
"},{"location":"quality-assurance/unit-testing/#test-location","title":"Test Location","text":"Kura discourages to introduce test-only dependencies on the implementation level, so all tests are located in their own projects under test/
. The proper folder to put the tests in is src/test/java
.
<package name>.test
as the name of the test project. Add it as a module in test/pom.xml
that also serves as maven artifact's parent.src/main/java
to build.properties' source..
.The basic flow is to build your implementation using maven and then also build and run the unit tests using mvn clean test
(or some other phase e.g. install, which also runs integration tests).
Advanced test running and running them in IDE is described in Kura GitHub Wiki.
"},{"location":"quality-assurance/unit-testing/#integration-testing","title":"Integration Testing","text":"These test proper behavior in the OSGi environment. Some additional configuration is therefore necessary.
"},{"location":"quality-assurance/unit-testing/#test-location_1","title":"Test Location","text":"We don't want to mess with the implementation code here, either, so all tests are again located in the test projects under test/
. It can be the same project as for unit tests. The proper folder to put the tests in is src/main/java
.
<package name>.test
as the name of the test project. Add it as a module in test/pom.xml
that also serves as maven artifact's parent.src/main/java
to build.properties' source..
.<package name>.test
as the package to put the test in. Also add .test
suffix to any subpackages that are also under test.The basic flow is to build your implementation using maven and then also build and run the integration tests using mvn clean install
.
Advanced test running and running them in IDE is described in Kura GitHub Wiki.
"},{"location":"references/javadoc/","title":"Javadoc","text":"This section provides guidelines on how to structure the MQTT topic namespace for messaging interactions with applications running on IoT gateway devices.
Interactions may be solicited by a remote server to the gateway using a request/response messaging model, or unsolicited when the gateway simply reports messages or events to a remote server based on periodic or event-driven patterns.
The table below defines some basic terms used in this document:
Term Descriptionaccount_name
Identifies a group of devices and users. It can be seen as partition of the MQTT topic namespace. For example, access control lists can be defined so that users are only given access to the child topics of a given account_name
. client_id
Identifies a single gateway device within an account (typically the MAC address of a gateway\u2019s primary network interface). The client_id maps to the Client Identifier (Client ID) as defined in the MQTT specifications. app_id
Unique string identifier for application (e.g., \u201cCONF-V1\u201d, \u201cCONF-V2\u201d, etc.). resource_id
Identifies a resource(s) that is owned and managed by a particular application. Management of resources (e.g., sensors, actuators, local files, or configuration options) includes listing them, reading the latest value, or updating them to a new value. A resource_id may be a hierarchical topic, where, for example, \u201csensors/temp\u201d may identify a temperature sensor and \u201csensor/hum\u201d a humidity sensor. A gateway, as identified by a specific client_id and belonging to a particular account_name, may have one or more applications running on it (e.g., \u201capp_id1\u201d, \u201capp_id2\u201d, etc.). Each application can manage one or more resources identified by a distinct resource_id(s).
Based on this criterion, an IoT application running on an IoT gateway may be viewed in terms of the resources it owns and manages as well as the unsolicited events it reports.
"},{"location":"references/mqtt-namespace/#mqtt-requestresponse-conversations","title":"MQTT Request/Response Conversations","text":"Solicited interactions require a request/response message pattern to be established over MQTT. To initiate a solicited conversation, a remote server first sends a request message to a given application running on a specific device and then waits for a response.
To ensure the delivery of request messages, applications that support request/response conversations via MQTT should subscribe to the following topic on startup:
$EDC/account_name/client_id/app_id/#\n
The $EDC prefix is used to mark topics that are used as control topics for remote management. This prefix distinguishes control topics from data topics that are used in unsolicited reports and marks the associated messages as transient (not to be stored in the historical data archive, if present).
Note
While Kura currently requires \u201c$EDC\u201d as the prefix for control topics, this prefix may change in the future for the following reasons:
MQTT 3.1.1 discourages the use of topic starting with \u201c$\u201d for application purposes.
As a binding of LWM2M over MQTT is taking shape, it would make sense to use a topic prefix for management messages like \u201cLWM2M\u201d or similar abbreviations (e.g. \"LW2\u201d, \u201cLWM\u201d).
A requester (i.e., the remote server) initiates a request/response conversation through the following events:
Generating a conversation identifier known as a request.id (e.g., by concatenating a random number to a timestamp)
Subscribing to the topic where the response message will be published, where requester.client.id is the client ID of the requester, such as:
$EDC/account_name/requester.client.id/app_id/REPLY/request.id\n
Sending the request message to the appropriate application-specific topic with the following fields in the payload:
The application receives the request, processes it, and responds on a REPLY topic structured as:
$EDC/account_name/requester.client.id/app_id/REPLY/request.id\n
Note
While this recommendation does not mandate the format of the message payload, which is application-specific, it is important that the request.id and requester.client.id fields are included in the payload. Kura leverages an MQTT payload encoded through Google Protocol Buffers. Kura includes the request.id and the requester.client.id as two named metrics of the Request messages. The Kura payload definition can be found here.
Once the response for a given request is received, the requester unsubscribes from the REPLY topic.
"},{"location":"references/mqtt-namespace/#mqtt-requestresponse-example","title":"MQTT Request/Response Example","text":"The following sample request/response conversation shows the device configuration being provided for an application:
account_name: guest\ndevice client_id: F0:D2:F1:C4:53:DB\napp_id: CONF-V1\nRemote Service Requester client_id: 00:E0:C7:01:02:03\n
The remote server publishes a request message similar to the following:
Request Topic:
Request Payload:
The gateway device replies with a response message similar to the following:
Response Topic:
Response Payload, where the following properties are mandatory:
Note
In addition to the mandatory properties, the response payload may also have custom properties whose description is beyond the scope of this document.
It is recommended that the requester server employs a timeout to control the length of time that it waits for a response from the gateway device. If a response is not received within the timeout interval, the server can expect that either the device or the application is offline.
"},{"location":"references/mqtt-namespace/#mqtt-remote-resource-management","title":"MQTT Remote Resource Management","text":"A remote server interacts with the application\u2019s resources through read, create and update, delete, and execute operations. These operations are based on the previously described request/response conversations.
"},{"location":"references/mqtt-namespace/#read-resources","title":"Read Resources","text":"An MQTT message published on the following topic is a read request for the resource identified by the resource_id:
$EDC/account_name/client_id/app_id/GET/resource_id\n
The receiving application responds with a REPLY message containing the latest value of the requested resource.
The resource_id is application specific and may be a hierarchical topic. It is recommended to design resource identifiers following the best practices established for REST API.
For example, if an application is managing a set of sensors, a read request issued to the topic \"$EDC/account_name/client_id/app_id/GET/sensors\" will reply with the latest values for all sensors.
Similarly, a read request issued to the topic \"$EDC/account_name/client_id/app_id/GET/sensors/temp\" will reply with the latest value for only a temperature sensor that is being managed by the application.
"},{"location":"references/mqtt-namespace/#create-or-update-resources","title":"Create or Update Resources","text":"An MQTT message published on the following topic is a create or update request for the resource identified by the resource_id:
$EDC/account_name/client_id/app_id/PUT/resource_id\n
The receiving application creates the specified resource (or updates it if it already exists) with the value supplied in the message payload and responds with a REPLY message.
As in the read operations, the resource_id is application specific and may be a hierarchical topic. It is recommended to design resource identifiers following the best practices established for REST API. For example, to set the value for an actuator, a message can be published to the topic \"$EDC/account_name/client_id/app_id/PUT/actuator/1\" with the new value suplliied in the message payload.
"},{"location":"references/mqtt-namespace/#delete-resources","title":"Delete Resources","text":"An MQTT message published on the following topic is a delete request for the resource identified by the resource_id:
$EDC/account_name/client_id/app_id/DEL/resource_id\n
The receiving application deletes the specified resource, if it exists, and responds with a REPLY message.
"},{"location":"references/mqtt-namespace/#execute-resources","title":"Execute Resources","text":"An MQTT message published on the following topic is an execute request for the resource identified by the resource_id:
$EDC/account_name/client_id/app_id/EXEC/resource_id\n
The receiving application executes the specified resource, if it exists, and responds with a REPLY message. The semantics of the execute operation is application specific.
"},{"location":"references/mqtt-namespace/#other-operations","title":"Other Operations","text":"The IoT application may respond to certain commands, such as taking a snapshot of its configuration or executing an OS-level command. The following topic namespace is recommended for command operations:
$EDC/account_name/client_id/app_id/EXEC/command_name\n
An MQTT message published with this topic triggers the execution of the associated command. The EXEC message may contain properties in the MQTT payload that can be used to parameterize the command execution.
"},{"location":"references/mqtt-namespace/#mqtt-unsolicited-events","title":"MQTT Unsolicited Events","text":"IoT applications have the ability to send unsolicited messages to a remote server using events to periodically report data readings from their resources, or to report special events and observed conditions.
Tip
It is recommended to not use MQTT control topics for unsolicited events, and subsequently, to avoid the $EDC topic prefix.
Event MQTT topics generally follow the pattern shown below to report unsolicited data observations for a given resource:
account_name/client_id/app_id/resource_id\n
"},{"location":"references/mqtt-namespace/#discoverability","title":"Discoverability","text":"The MQTT namespace guidelines in this document do not address remote discoverability of a given device\u2019s applications and its resources. The described interaction pattern can be easily adopted to define an application whose only responsibility is reporting the device profile in terms of installed applications and available resources.
"},{"location":"references/mqtt-namespace/#remote-osgi-management-via-mqtt","title":"Remote OSGi Management via MQTT","text":"The concepts previously described have been applied to develop a solution that allows for the remote management of certain aspects of an OSGi container through the MQTT protocol, including:
Remote deployment of application bundles
Remote start and stop of services
Remote read and update of service configurations
The following sections describe the MQTT topic namespaces and the application payloads used to achieve the remote management of an OSGi container via MQTT.
Note
For the scope of this document, some aspects concerning the encoding and compressing of the payload are not included.
The applicability of the remote management solution, as inspired by the OSGi component model, can be extended beyond OSGi as the contract with the managing server based on MQTT topics and XML payloads.
"},{"location":"references/mqtt-namespace/#remote-osgi-configurationadmin-interactions-via-mqtt","title":"Remote OSGi ConfigurationAdmin Interactions via MQTT","text":"An application bundle is installed in the gateway to allow for remote management of the configuration properties of the services running in the OSGi container.
For information about the OSGi Configuration Admin Service and the OSGi Meta Type Service, please refer to the OSGi Service Platform Service R7 Specifications.
The app_id for the remote configuration service of an MQTT application is \u201cCONF-V1\u201d. The resources it manages are the configuration properties of the OSGi services. Service configurations are represented in XML format.
The following service configuration XML message is an example of a watchdog service:
<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<ns2:configuration xmlns:ns2=<http://eurotech.com/esf/2.0\n xmlns=<http://www.osgi.org/xmlns/metatype/v1.2.0>\n pid=\"org.eclipse.kura.watchdog.WatchdogService\">\n\n <OCD id=\"org.eclipse.kura.watchdog.WatchdogService\"\n name=\"WatchdogService\"\n description=\"WatchdogService Configuration\">\n\n <Icon resource=\"WatchdogService\"/>\n\n <AD id=\"watchdog.timeout\"\n name=\"watchdog.timeout\"\n required=\"true\"\n default=\"10000\"\n cardinality=\"0\"\n type=\"Integer\"\n description=\"\"/>\n </OCD>\n\n <ns2:properties>\n <ns2:property type=\"Integer\" array=\"false\" name=\"watchdog.timeout\">\n <ns2:value>10000</ns2:value>\n </ns2:property>\n </ns2:properties>\n</ns2:configuration>\n
The service configuration XML message is comprised of the following parts:
The Object Class Definition (OCD), which describes the service attributes that may be configured. (The syntax of the OCD element is described in the OSGi Service Platform Service R7 Specifications)
The properties element, which contains one or more properties with their associated type and values. The type name must match the name provided in the corresponding attribute definition identifier (AD id) contained in the OCD.
The \u201cCONF-V1\u201d application supports the read and update resource operations as described in the following sections.
"},{"location":"references/mqtt-namespace/#read-all-configurations","title":"Read All Configurations","text":"This operation provides all service configurations for which remote administration is supported.
Request Topic:
Request Payload:
Response Payload:
This operation provides configurations for a specific service that is identified by an OSGi service persistent identifier pid.
Request Topic:
Request Payload:
Response Payload:
This operation remotely updates the configuration of a set of services.
Request Topic:
Request Payload:
Response Payload:
This operation remotely updates the configuration of the service identified by a pid.
Request Topic:
Request Payload:
Response Payload:
The previously described read and update resource operations can be leveraged to develop a web application that allows for remote OSGi service configuration updates via MQTT though a web user-interface.
The screen capture that follows shows an example administration application where, for a given IoT gateway, a list of all configurable services is presented to the administrator.
When one such service is selected, a form is dynamically generated based on the metadata provided in the service OCD. This form includes logic to handle different attribute types, validate acceptable value ranges, and render optional values as drop-downs. When the form is submitted, the new values are communicated to the device through an MQTT resource update message.
"},{"location":"references/mqtt-namespace/#remote-osgi-deploymentadmin-interactions-via-mqtt","title":"Remote OSGi DeploymentAdmin Interactions via MQTT","text":"An application is installed in the gateway to allow for the remote management of the deployment packages installed in the OSGi container.
For information about the OSGi Deployment Admin Service, please refer to the OSGi Service Platform Service Compendium 4.3 Specifications.
The app_id for the remote deployment service of an MQTT application is \u201cDEPLOY-V2\u201d. It allows to perform the following operations:
The download request allows to download and optionally install a software package. The installation procedure will be performed after the download completes if the dp.install metric is set to true
. If the metric is set to false
, the installation step will not be performed.
The package type must be specified using the dp.install.system.update request metric, the supported types are the following:
false
.true
.The device will report the download progress and result of the installation to the cloud platform by sending asynchronous download notification messages and install notification messages.
The completion notification logic differs depending on the package type.
OSGi Deployment Package: The completion notification will be sent immediately after that the Deployment Package is installed on the system.
Executable Shell Script: The completion notification will not be sent immediately after that the shell script is executed, but is determined by the execution of an additional verifier script. The verifier script will be executed at next framework startup. A install notification message will be sent afterwards, with dp.install.status = COMPLETED
if the exit status is 0 or dp.install.status = FAILED
otherwise. This is based on the assumption that a system level update will typically require a device restart.
The verifier script can be provided in the following ways:
By specifying a download URL as the value of the dp.install.verifier.uri request metric. In this case the framework will download the verifier script from the provided URL.
By installing it during the execution of the main shell script. In this case the file must be placed in the /opt/eclipse/kura/data/persistance/verification
directory. The installed verifier file name must have the ${name}-${version}.sh_verifier.sh
structure where ${name}
and ${version}
must be replaced with the values of the dp.name and dp.version request metrics.
Warning
As said above, in case of Executable Shell Script, the completion notification will not be sent if the verifier script is not provided and/or the framework is not restarted.
Request:
Request Topic:
Payload:
Response:
The client will reply immediately with an appropriate response.code. If the platform retries the request but the download is in progress, the client will reply that the request is already in progress with a 500 error code. If the DP has already been downloaded, the client will reply that the request has been accepted. If the dp.download.force flag is set to true, the client will start the download from the beginning, if false the device will proceed with the installation.
Payload: no application-specific metrics or body.
Request:
Response:
Request:
Response:
The client will start downloading the DP and will compute the size of the transfer from the HTTP header. This size will be used to estimate the download progress using the request parameter dp.download.block.size. Next, the client will report the download progress to the platform by publishing, with QoS==2, one or more unsolicited messages. If HTTP header is not available, the device will report 50% as dp.download.progress for all the download processes. The value of requester.client.id is one of the last downloads or install request received.
Download Notification:
Request:
Note
This operation can be retried. Anyway, if it fails once it's likely to fail again.
Response:
Request:
Response:
If the value of dp.install in the original download request is true the client will start installing the DP. Due to the limitations of the OSGi DeploymentAdmin, it's not possible to have feedback on the install progress. However, these operations should normally complete in a few seconds, even for an upgrade. Otherwise (dp.install==false), the platform can request the installation of an already downloaded package through the following message:
Install notification:
Request:
Response: The client will reply immediately with an appropriate response.code. If the platform retries the request but the uninstall operation is in progress, the client will reply that the request is already in progress with a 500 error code. At the end of the uninstall operation, an unsolicited message is sent to the cloud platform to report the operation status. If a reboot was requested in the received uninstall request, it will be executed with the specified delay.
"},{"location":"references/mqtt-namespace/#unsolicited-messages-for-uninstall-progress","title":"Unsolicited messages for uninstall progress","text":"Uninstall notification:
This operation provides all the bundles installed in the OSGi framework.
The following XML message is an example of a bundle:
<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<bundles>\n <bundle>\n <name>org.eclipse.osgi</name>\n <version>3.8.1.v20120830-144521</version>\n <id>0</id>\n <state>ACTIVE</state>\n </bundle>\n <bundle>\n <name>org.eclipse.equinox.cm</name>\n <version>1.0.400.v20120522-1841</version>\n <id>1</id>\n <state>ACTIVE</state>\n </bundle>\n</bundles>\n
The bundle XML message is comprised of the following bundle elements:
This operation starts a bundle identified by its ID.
This operation stops a bundle identified by its ID.
The previously described read, start/stop, and install/uninstall resources can be used to implement a remote management application. An example of such application is Eclipse Kapua. In particular it is possible to use the download and install resources from the following sections in Eclipse Kapua console:
Selecting the Devices section, a target device, and then clicking on the Install button in the Packages tab will allow to send download and install requests.
It is possible to create a batch job with the Package Download / Install definition to perform a download / install request on a set of target devices.
"},{"location":"references/mqtt-namespace/#remote-gateway-inventory-via-mqtt","title":"Remote Gateway Inventory via MQTT","text":"An application is installed in the gateway to allow for the remote query of the resources installed in the OSGi container and the underlying OS.
The app_id for the remote inventory service of an MQTT application is \u201cINVENTORY-V1\u201d. The service allows retrieving all the different resources available/installed on the gateway. The service supports the following resources:
The resources are represented in JSON format. The following message is an example of a service deployment:
{\n \"inventory\":[\n {\n \"name\":\"adduser\",\n \"version\":\"3.118\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"io.netty.transport-native-unix-common\",\n \"version\":\"4.1.34.Final\",\n \"type\":\"BUNDLE\"\n },\n ]\n}\n
The inventory JSON message is comprised of the following package elements:
Name
Version
Type
The \u201cINVENTORY-V1\u201d application supports only the read resource operations as described in the following sections.
"},{"location":"references/mqtt-namespace/#inventory-bundles","title":"Inventory Bundles","text":""},{"location":"references/mqtt-namespace/#read-all-bundles_1","title":"Read All Bundles","text":"This operation provides all the bundles installed in the OSGi framework.
Request Topic:
Request Payload:
Response Payload:
The following JSON message is an example of a bundle:
{\n \"bundles\":[\n {\n \"name\":\"org.eclipse.osgi\",\n \"version\":\"3.16.0.v20200828-0759\",\n \"id\":0,\n \"state\":\"ACTIVE\",\n \"signed\":true\n },\n {\n \"name\":\"org.eclipse.equinox.cm\",\n \"version\":\"1.4.400.v20200422-1833\",\n \"id\":1,\n \"state\":\"ACTIVE\",\n \"signed\":false\n }\n ]\n}\n
The bundle JSON message is comprised of the following bundle elements:
Symbolic name
Version
ID
State
Signed
This operation allows to start a bundles installed in the OSGi framework.
Request Topic:
Request Payload:
Response Payload:
Request Topic:
Request Payload:
Response Payload:
The requests for starting and stopping a bundle require the application to include a JSON object in request payload for selecting the target bundle, the defined properties are the following:
If multiple bundles match the selection criteria, only one of them will be stopped/started, which one is not defined.
Examples:
{\n \"name\":\"org.eclipse.kura.example.beacon\"\n}\n
{\n \"name\":\"org.eclipse.kura.example.beacon\",\n \"version\":\"1.0.500\"\n}\n
"},{"location":"references/mqtt-namespace/#inventory-deployment-packages","title":"Inventory Deployment Packages","text":""},{"location":"references/mqtt-namespace/#read-all-deployment-packages","title":"Read All Deployment Packages","text":"This operation provides the deployment packages installed in the OSGi framework.
Request Topic:
Request Payload:
Response Payload:
The following JSON message is an example of a bundle:
{\n \"deploymentPackages\":[\n {\n \"name\":\"org.eclipse.kura.example.beacon\",\n \"version\":\"1.0.500\",\n \"signed\":false,\n \"bundles\":[\n {\n \"name\":\"org.eclipse.kura.example.beacon\",\n \"version\":\"1.0.500\",\n \"id\": 171,\n \"state\": \"ACTIVE\",\n \"signed\": false\n }\n ]\n }\n ]\n}\n
The deployment package JSON message is comprised of the following package elements:
Symbolic name
Version
Signature: true if all the bundles in the deployment package are signed
Bundles that are managed by the deployment package along with their symbolic name and version
This operation provides the Linux packages installed in OS.
Request Topic:
Request Payload:
Response Payload:
The following JSON message is an example of a bundle:
{\n \"systemPackages\":[\n {\n \"name\":\"adduser\",\n \"version\":\"3.118\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"alsa-utils\",\n \"version\":\"1.1.8-2\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"ansible\",\n \"version\":\"2.7.7+dfsg-1\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"apparmor\",\n \"version\":\"2.13.2-10\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"apt\",\n \"version\":\"1.8.2.1\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"apt-listchanges\",\n \"version\":\"3.19\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"apt-transport-https\",\n \"version\":\"1.8.2.2\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"apt-utils\",\n \"version\":\"1.8.2.1\",\n \"type\":\"DEB\"\n }\n ]\n}\n
The bundle JSON message is comprised of the following bundle elements:
Name
Version
Type
Using the API exposed by Inventory-V1, the user can manage containers via external applications such as Eclipse Kapua. This operation lists all the containers installed in the gateway.
The following JSON message is an example of what this request outputs:
{\n \"containers\":\n [\n {\n \"name\":\"container_1\",\n \"version\":\"nginx:latest\",\n \"type\":\"DOCKER\",\n \"state\":\"active\"\n }\n ]\n}\n
The container JSON message is comprised of the following elements:
Name: The name of the docker container.
Version: describes both the container's respective image and tag separated by a colon.
Type: denotes the type of inventory payload
State: describes the container's current state
active
: Container is runninginstalled
: Container is startinguninstalled
: Container has failed, or is stoppedunknown
: Container state can not be determinedThis operation allows starting a container installed on the gateway. * Request Topic * $EDC/account_name/client_id/INVENTORY-V1/EXEC/containers/_start * Request Payload * A JSON object that identifies the target container must be specified in the payload body. This payload will be described in the following section * Response Payload * Nothing application-specific
"},{"location":"references/mqtt-namespace/#stop-a-container","title":"Stop a Container","text":"The requests for starting and stopping a container require the application to include a JSON object in the request payload for selecting the target container. Docker enforces unique container names on a gateway, and thus they can reliably be used as an identifier.
Examples:
{\n \"name\":\"container_1\",\n \"version\":\"nginx:latest\",\n \"type\":\"DOCKER\",\n \"state\":\"active\"\n}\n
{\n \"name\":\"container_1\",\n}\n
"},{"location":"references/mqtt-namespace/#inventory-container-images","title":"Inventory Container Images","text":""},{"location":"references/mqtt-namespace/#list-all-images","title":"List All Images","text":"Using the API exposed by Inventory-V1, the user can manage container images via external applications such as Eclipse Kapua. This operation lists all the images in the gateway.
The following JSON message is an example of what this request outputs:
{\n \"images\":\n [\n {\n \"name\":\"nginx\",\n \"version\":\"latest\",\n \"type\":\"CONTAINER_IMAGE\"\n }\n ]\n}\n
The container JSON message is comprised of the following elements:
Name: The name of the container image.
Version: describes the container image's version.
Type: denotes the type of inventory payload
This operation allows deleting a container image not in use on the gateway. * Request Topic * $EDC/account_name/client_id/INVENTORY-V1/EXEC/images/_delete * Request Payload * A JSON object that identifies the target image must be specified in the payload body. This payload will be described in the following section * Response Payload * Nothing application-specific
"},{"location":"references/mqtt-namespace/#json-identifierpayload-for-container-image-delete-requests","title":"JSON identifier/payload for container image delete requests","text":"The requests for deleting a container image require the application to include a JSON object in the request payload for selecting the target. The JSON requires both name and version fields to be populated.
Examples:
{\n \"name\":\"nginx\",\n \"version\":\"latest\",\n \"type\":\"CONTAINER_IMAGE\"\n}\n
{\n \"name\":\"nginx\",\n \"version\":\"latest\",\n}\n
"},{"location":"references/mqtt-namespace/#inventory-summary","title":"Inventory Summary","text":""},{"location":"references/mqtt-namespace/#read-all-resources","title":"Read All Resources","text":"This operation provides a list of all the resources installed on the gateway
Request Topic:
Request Payload:
Response Payload:
The following JSON message is an example of a bundle:
{\n \"inventory\":[\n {\n \"name\":\"adduser\",\n \"version\":\"3.118\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"com.eclipsesource.jaxrs.provider.gson\",\n \"version\":\"2.3.0.201602281253\",\n \"type\":\"BUNDLE\"\n },\n {\n \"name\":\"org.eclipse.kura.example.beacon\",\n \"version\":\"1.0.500\",\n \"type\":\"DP\"\n }\n ]\n}\n
The bundle JSON message is comprised of the following bundle elements:
Name
Version
Type
The KEYS-V1 app-id is exposed by the org.eclipse.kura.core.keystore
bundle. This request handler allows the remote management platform to get a list of all the KeystoreService instances and corresponding keys managed by the framework in a given device.
The request handler allows, also, to install new trusted certificate and to generate new key pairs directly in the device. Finally, the remote platform can request, from a defined key pair, the generation of a CSR that can be countersigned remotely by a trusted CA.
"},{"location":"references/mqtt-namespace/#read-all-the-kestoreservices","title":"Read All the KestoreServices","text":"This operation returns the list of all the KeystoreServices instantiated in the framework.
Request Topic:
Request Payload:
Response Payload:
The following JSON message is an example of an output provided:
[\n {\n \"id\": \"org.eclipse.kura.core.keystore.SSLKeystore\",\n \"type\": \"jks\",\n \"size\": 4\n },\n {\n \"id\": \"org.eclipse.kura.crypto.CryptoService\",\n \"type\": \"jks\",\n \"size\": 3\n },\n {\n \"id\": \"org.eclipse.kura.core.keystore.HttpsKeystore\",\n \"type\": \"jks\",\n \"size\": 1\n },\n {\n \"id\": \"org.eclipse.kura.core.keystore.DMKeystore\",\n \"type\": \"jks\",\n \"size\": 1\n }\n]\n
Each entry of the array is specified by the following values: This operation returns the list of all the key entries managed by the framework. If a request payload is specified, the list of entries is filtered based on the parameters in the request
Request Topic:
Request Payload:
{\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.SSLKeystore\"\n}\n
{\n\"alias\": \"ca-godaddyclass2ca\"\n}\n
Response Payload:
The following JSON message is an example of an output provided in the response body:
[\n {\n \"subjectDN\": \"OU=Go Daddy Class 2 Certification Authority, O=\\\"The Go Daddy Group, Inc.\\\", C=US\",\n \"issuer\": \"OU=Go Daddy Class 2 Certification Authority,O=The Go Daddy Group\\\\, Inc.,C=US\",\n \"startDate\": \"Tue, 29 Jun 2004 17:06:20 GMT\",\n \"expirationDate\": \"Thu, 29 Jun 2034 17:06:20 GMT\",\n \"algorithm\": \"SHA1withRSA\",\n \"size\": 2048,\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.SSLKeystore\",\n \"alias\": \"ca-godaddyclass2ca\",\n \"type\": \"TRUSTED_CERTIFICATE\"\n },\n {\n \"algorithm\": \"RSA\",\n \"size\": 4096,\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.HttpsKeystore\",\n \"alias\": \"localhost\",\n \"type\": \"PRIVATE_KEY\"\n }\n]\n
"},{"location":"references/mqtt-namespace/#read-key-details","title":"Read Key Details","text":"This operation returns the details associated to a specified key in a keystore
Request Topic:
Request Payload:
keystoreServicePid
and the alias
of the desired key {\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.HttpsKeystore\"\n \"alias\": \"localhost\"\n}\n
* Response Payload: * List of all the details associated to a key managed by the framework The following JSON message is an example of an output provided:
{\n \"algorithm\": \"RSA\",\n \"size\": 4096,\n \"certificateChain\": [\n \"-----BEGIN CERTIFICATE-----\\nMIIFkTCCA3mgAwIBAgIECtXoiDANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJJ\\nVDELMAkGA1UECBMCVUQxDjAMBgNVBAcTBUFtYXJvMREwDwYDVQQKEwhFdXJvdGVj\\naDEMMAoGA1UECxMDRVNGMQwwCgYDVQQDEwNFU0YwHhcNMjEwNDIyMTUxNTU1WhcN\\nMjQwMTE3MTUxNTU1WjBZMQswCQYDVQQGEwJJVDELMAkGA1UECBMCVUQxDjAMBgNV\\nBAcTBUFtYXJvMREwDwYDVQQKEwhFdXJvdGVjaDEMMAoGA1UECxMDRVNGMQwwCgYD\\nVQQDEwNFU0YwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC7iZ3fHUQa\\nTPgnvSxGZK4f6MZYfLclD74yqaCCWAztNxPQoiBoSPGdsBGBLNeFbwY0Yzg3qwXw\\nYvgzLJmoXV9rSix7LgXPzsSYfUGfu7PeYTy5bG9X2UVyw9LloUM5DKnw++5F7Xy7\\nF0KQQi0z6/HbbPkZ2aGyNRtMCTh1iAGy3gDh/mMnjpUYuoq1luoX1x6I77X0C+NP\\nTxldVYrTeQiswItAHZmkK1R8AYedbFBgjDuTrfRODxBwESn4kQSMLJ8yHYDRm8S6\\ngVz5LdkcM48UiV5hhF+bCD3UvYA00ZgZm2oOG1ONchYrE7pJr7eQVCYaXkS1lALB\\nKaVJzn03wiLJJv1FYLmGt5J/MwfqyCtBTLlieEVfwnxFCkymtews6SYK32e9q/uJ\\nfcdpWH7tOoarnAf7j5mE84rRU3HqzghK0bMxntfrSH3t18ZUt1/4Qx78WfiM1Te3\\nJtnWBqUNJtX6lgT8IxTWwyEqD183tyKIo8hPGyeJrzWA5RL5hYF5rCNTWzqz5Upi\\n0b/YI5K09+Rn8XmEzzaWjFq5zu6/WpqwPRA8kc2RAEA2scnOT+3yl9Lof/M7BrfL\\nMdjVOZ4MfXgl/fhFyd16AObXuZRUIeiWowKtEiNaiUn8paLDxG+LNV7p5wEQCZZI\\n+MsXMMp6G8Te4yILLCcGov7OkO2wx4GPWQIDAQABo2EwXzAxBgNVHSUEKjAoBggr\\nBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDBggrBgEFBQcDCDALBgNVHQ8EBAMC\\nAvwwHQYDVR0OBBYEFKM5PlHoe8qFC6w0quGacazGWE/LMA0GCSqGSIb3DQEBCwUA\\nA4ICAQBvpXmbS9LN8n0A+uq+tM3CNtF3YotWRbQHIGJAFTvdq3003W3CVdmykFc8\\n9Kz8PoY1swBJms7GKjQLkqgTHoq6jU/cIXw+CoLQWmvAugva5C1u/5AHJZqTC06J\\nGZyn1Z9N5Lp0XcgogEyhxdbkHniv7jvcmbCurQijZc9nsd5St7e1pT0Co7KKI6Ff\\nODdVP6kZYBzKo4t20tATdAZJ8t7YHNKNq7ZVs1ej9oYUmmQieNXuE4UoHe5hzVQw\\n567cNHWcTHJoyPve03TSQV91wp5rRUKZm2p0WtFNuv22f5p5sQmttsJltzHCgTwE\\nK0j6qYKnXiq+EQs0A3uF9uiIB/KEDLjxscstqsQGFCFOmjA3GSbmJiKCnss3HkNn\\naknT7XCV6tqgDOfPnNzbWJODjYZ+V0DyNY5uqkG2cyREm/qGbH1kLEXhqdWbKqEs\\nsdW6x8p0ImTaPuRl3XEmXbolavIq+FTtOSz8vW1PsdD3quO6krrwiQMXKv1ZMjup\\nDGIZZ4hUUhN84efjlZyoFRvPRvZ8YvjjrHXLij0vcRxndlicevwl5ezlm0LBOpsT\\nkI2uWrbSbxlue/XdgwFCbN0+mXX88fGj6cjhpvd/xnwHaDHfSG9UoU149LJb6ZIZ\\nru+07QriQQxK8V7AdPr6bhmKPxbbFenvSQmsmgjAY93qtanbNg==\\n-----END CERTIFICATE-----\"\n ],\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.HttpsKeystore\",\n \"alias\": \"localhost\",\n \"type\": \"PRIVATE_KEY\"\n}\n
"},{"location":"references/mqtt-namespace/#create-csr","title":"Create CSR","text":"This operation returns the CSR for a specific key pair managed by the framework
Request Topic:
Request Payload:
{ \n \"keystoreServicePid\":\"org.eclipse.kura.core.keystore.HttpsKeystore\",\n \"alias\":\"localhost\",\n \"signatureAlgorithm\" : \"SHA256withRSA\",\n \"attributes\" : \"CN=Kura, OU=IoT, O=Eclipse, C=US\"\n}\n
Response Payload:
-----BEGIN CERTIFICATE REQUEST-----\nMIIEgTCCAmkCAQAwPDELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VjbGlwc2UxDDAK\nBgNVBAsTA0lvVDENMAsGA1UEAxMES3VyYTCCAiIwDQYJKoZIhvcNAQEBBQADggIP\nADCCAgoCggIBAICTNbBm2wIV/TvddB3OW2s2WJmhAOBxwDSdpxGpgWDzmFAydCt5\nSfWCIeC0kmQfrJpcvcIB7IoE2I7HWtIOxV9c+E+n6R76NvdBQzB8enFfZu4ahIKy\nul2VXQSj0VtYLZvG3yx6af4j8UFWsf2AuAe5Fd1dSBq9aEoRU/D5/uNQOQJi45Hk\nds1KK0FcTkfPjugUCLf1Uf0xXnK1V7yZGrgDpPDbZAYCrcsGomdziO8zkE88gKaa\noC1madGL44yz5tiHTKvbf+O+fKc31N4iDvnIg8f87IMF0D4afDF+3AJjVfcFtp3Q\nxWP3zpKqzPzpzWagTzsW446YMxamZgkDxLsVLitQtesom4ON3HT8s+jxHQhCO5LR\n83Ge10+6viJtkp20GYCqANO85c3TaD9njOE0y8P/T7Nk8MwnBbVgwa15QEWRqjEd\nHB6dF5jKdxlfZhPe2AVnLWAd/W96tCIBSqYu6TTH8npprp/S4t10tRkpaLGa+24c\nVlsjR6AFUX4KksvE/mbXd9QsvKgw/h3g4Jly4W/Ourt1LAH19tzGwULNCS7Ft9rp\nIXUsbmUUwb0V3B3ptcJUDzPUw8LdbItPnXzaPegxmkHO8IllcrdRBXrpcTwJl1ug\nMTMWKW/UjUwKcNQ0mGIxQ18aS0mHk8x8bVTnYLcCnGq3NeiFWvOiJIJpAgMBAAGg\nADANBgkqhkiG9w0BAQsFAAOCAgEATsHVZAEjkMSpwozWbVvDw4iJOSYaQ7ZJXhGZ\nn81puMy/kcdNVD2hfG2c4ern8KPib6hYd1mbQpyNtsbJ68VOPIYOdiaqFd7+lbtM\nIVNETBA9ezXzzXwPCtiJYpmeDYz6HfIzRRzuoJhZtOrgyw8v5wiM0NkenDbTQs4l\nOd/YPFlHnEDkTNM+B/ZJJxRIg3sPhAAgj5HH0Mj2053z66hLDYAo4Tos98MwUcuA\ndY1pcs3brxg6z7xz4vbNKyj0Lh8Gua92OSbl1AFZYb6KXm/7+Md0la/YD+K/E2n6\nhUAcHkr3ayNuTI6lkQFptCHzb4Zr8rdbu63JRno9PFTnW+fa/0xi35DoHD2SAhwA\nCUGXTR+HQXkzB/9NE9X0TxS8SwyrE8sfw4usZm25tACdZ33xziqJXOmbChETyL2b\nJ1IcbsHaeN2Shjnj7UQj+hQFnjVwRLTd0zWMN/l7mPj6TiW9ehubE8ce5siHW7NO\nmqJU1bklxTefefSNHTXrvTInuDXT81gLBRE3x+6uqU2kkJnL8jkrkebDDBhYF+qO\n6dB4W5WGbEHxorX2qfjImvy2Ohsl3rL/DqJgqECZaubTz1Xcj/kl9bdxs0pfa6IY\nInre5iom9bGcA6W6U34jRsrE2pobi6c9Yimrbr/R2O/8Oy2k94FQta8tg8jbAxBi\nZ0Vd1nM=\n-----END CERTIFICATE REQUEST-----\n
This operation stores the provided certificate as a Trusted Certificate Entry managed by the framework
Request Topic:
Request Payload:
{\n \"keystoreServicePid\":\"MyKeystore\",\n \"alias\":\"myCertTest99\",\n \"certificate\":\"-----BEGIN CERTIFICATE-----\n MIIDdzCCAl+gAwIBAgIEQsO0gDANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdV\n bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD\n VQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3du\n MB4XDTIxMDQxNDA4MDIyOFoXDTIxMDcxMzA4MDIyOFowbDEQMA4GA1UEBhMHVW5r\n bm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UE\n ChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCC\n ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJSWJDxu8UNC4JGOgK31WCvz\n NKy2ONH+jTVKnBY7Ckb1hljJY0sKO55aG1HNDfkev2lJTsPIz0nJjNsqBvB1flvf\n r6XVCxdN0yxvU5g9SpRxE/iiPX0Qt7463OfzyKW97haJrrhF005RHYNcORMY/Phj\n hFDnZhtAwpbQLzq2UuIZ7okJsx0IgRbjH71ZZuvYCqG7Ct/bp1D7w3tT7gTbIKYH\n ppQyG9rJDEh9+cr9Hyk8Gz7aAbPT/wMH+/vXDjH2j/M1Tmed0ajuGCJumaTQ4eHs\n 9xW3B3ugycb6e7Osl/4ESRO5RQL1k2GBONv10OrKDoZ5b66xwSJmC/w3BRWQ1cMC\n AwEAAaMhMB8wHQYDVR0OBBYEFPospETb5HNeD/DmS9mwt+v/AYq/MA0GCSqGSIb3\n DQEBCwUAA4IBAQBxMe1xQVQKt36A5qVlEZyxI9eb6eQRlYzorOgP2tFaOsvDPpRI\n CALhPmxgQl/5QvKFfCXKoxWj1Spg4sF6fJp6jhSjLpmChS9lf5fRaWS20/pxIddM\n 10diq3r6HxLKSxCYK7Pf5scOeZquvwfo8Kxye01bvCMFf1s1K3ZEZszk5Oo2MnWU\n U22YnXfZm1C0h2WMUcou35A7CeVAHPWI0Rvefojv1qYlQScJOkCN5lO6C/1qvRhq\n nDQdQN/m1HQbpfh2DD6F33nBjkyLQyMRF8uMnspLrLLj8lecSTJZO4fGJOaIXh3O\n 44da9A02FAf5nRRQpwP2x/4IZ5RTRBzrqbqD\n -----END CERTIFICATE-----\"\n}\n
Response Payload:
This operation will generate a new key pair directly in the device, based on the parameters received from the request
Request Topic:
Request Payload:
{\n \"keystoreServicePid\":\"MyKeystore\",\n \"alias\":\"keypair1\",\n \"algorithm\" : \"RSA\",\n \"size\": 1024,\n \"signatureAlgorithm\" : \"SHA256WithRSA\",\n \"attributes\" : \"CN=Kura, OU=IoT, O=Eclipse, C=US\"\n}\n
Response Payload:
This operation will delete the specified entry from the framework managed keystores
Request Topic:
Request Payload:
{\n \"keystoreServicePid\" : \"MyKeystore\",\n \"alias\" : \"mycerttestec\"\n}\n
Response Payload:
Starting from Kura 5.4.0, the KEYS-V2
request handler is also available, it supports all of the request endpoints of KEYS-V1
plus an additional endpoint that allows to upload and modify private key entries:
Request Topic:
Request Payload:
The request should include the private key in unencrypted PEM format and the certificate chain in PEM format, the first certificate in the certificateChain
list must use the public key associated with the private key supplied as the privateKey
parameter.
The device will overwrite the entry with the provided alias if it already exists.
{\n \"keystoreServicePid\":\"MyKeystore\",\n \"alias\":\"keypair1\",\n \"privateKey\":\"-----BEGIN RSA PRIVATE KEY-----\\n...\\n-----END RSA PRIVATE KEY-----\",\n \"certificateChain\":[\n \"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\",\n \"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\",\n ]\n}\n
Response Payload:
Request Topic:
Request Payload:
In order to update the certificate chain associated to a specific private key entry it is possible to use the same format as previous request and omit the privateKey
parameter.
In this case the certificate chain of the existing entry will be replaced with the one specified in the request and the existing private key will be retained.
This request can be useful for example to create a CSR on the device, sign it externally and then updating the corresponding entry with the resulting certificate.
{\n \"keystoreServicePid\":\"MyKeystore\",\n \"alias\":\"keypair1\",\n \"certificateChain\":[\n \"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\",\n \"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\",\n ]\n}\n
Response Payload:
Note
This API can also be accessed via the RequestHandler with app-id: CLD-V1
.
The CloudConnectionRestService
APIs provides methods to manage cloud connection related components like CloudEndpoint
, CloudPublisher
and CloudSubscriber
instances.
Identities with rest.cloudconnection
permissions can access these APIs.
services/cloudconnection/v1/instances
{\n \"cloudEndpointInstances\": [\n {\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloud.CloudService\",\n \"cloudEndpointPid\": \"org.eclipse.kura.cloud.CloudService\",\n \"state\": \"DISCONNECTED\",\n \"cloudEndpointType\": \"CLOUD_CONNECTION_MANAGER\"\n },\n {\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloud.CloudService\",\n \"cloudEndpointPid\": \"org.eclipse.kura.cloud.CloudService-todelete\",\n \"state\": \"DISCONNECTED\",\n \"cloudEndpointType\": \"CLOUD_CONNECTION_MANAGER\"\n },\n {\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloud.CloudService\",\n \"cloudEndpointPid\": \"org.eclipse.kura.cloud.CloudService-2\",\n \"state\": \"DISCONNECTED\",\n \"cloudEndpointType\": \"CLOUD_CONNECTION_MANAGER\"\n },\n {\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloud.CloudService\",\n \"cloudEndpointPid\": \"org.eclipse.kura.cloud.CloudService-3\",\n \"state\": \"DISCONNECTED\",\n \"cloudEndpointType\": \"CLOUD_CONNECTION_MANAGER\"\n },\n {\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloud.CloudService\",\n \"cloudEndpointPid\": \"org.eclipse.kura.cloud.CloudService-test\",\n \"state\": \"DISCONNECTED\",\n \"cloudEndpointType\": \"CLOUD_CONNECTION_MANAGER\"\n }\n ],\n \"pubsubInstances\": [\n {\n \"cloudEndpointPid\": \"org.eclipse.kura.cloud.CloudService\",\n \"pid\": \"testPub\",\n \"factoryPid\": \"org.eclipse.kura.cloud.publisher.CloudPublisher\",\n \"type\": \"PUBLISHER\"\n },\n {\n \"cloudEndpointPid\": \"org.eclipse.kura.cloud.CloudService\",\n \"pid\": \"testPub\",\n \"factoryPid\": \"org.eclipse.kura.cloud.publisher.CloudPublisher\",\n \"type\": \"SUBSCRIBER\"\n }\n ]\n}\n
cloudEndpointType
: The possible values are:
CLOUD_CONNECTION_MANAGER if the component implements CloudConnectionManager
CLOUD_ENDPOINT otherwise.
If cloudEndpointType
is CLOUD_CONNECTION_MANAGER, it is possible to use the cloudEndpoint/connect
, cloudEndpoint/disconnect
and cloudEndpoint/isConnected
methods to manage the connection state.
services/cloudconnection/v1/factories
{\n \"cloudConnectionFactories\": [\n {\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloud.CloudService\",\n \"defaultCloudEndpointPid\": \"org.eclipse.kura.cloud.CloudService-2\",\n \"cloudEndpointPidRegex\": \"^org.eclipse.kura.cloud.CloudService\\\\-[a-zA-Z0-9]+$\"\n },\n {\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager\",\n \"defaultCloudEndpointPid\": \"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager\",\n \"cloudEndpointPidRegex\": \"^org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager(\\\\-[a-zA-Z0-9]+)?$\"\n },\n {\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint\",\n \"defaultCloudEndpointPid\": \"org.eclipse.kura.cloudconnection.raw.mqtt.CloudEndpoint\",\n \"cloudEndpointPidRegex\": \"^org.eclipse.kura.cloudconnection.raw.mqtt.CloudEndpoint(\\\\-[a-zA-Z0-9]+)?$\"\n },\n {\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.camel.cloud.factory.CamelFactory\",\n \"defaultCloudEndpointPid\": \"org.eclipse.kura.camel.cloud.factory.CamelFactory\",\n \"cloudEndpointPidRegex\": \"^org.eclipse.kura.camel.cloud.factory.CamelFactory(\\\\-[a-zA-Z0-9]+)?$\"\n }\n ],\n \"pubSubFactories\": [\n {\n \"factoryPid\": \"org.eclipse.kura.cloudconnection.raw.mqtt.subscriber.RawMqttSubscriber\",\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint\"\n },\n {\n \"factoryPid\": \"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher\",\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager\",\n \"defaultPid\": \"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher\",\n \"defaultPidRegex\": \"^org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher(\\\\-[a-zA-Z0-9]+)?$\"\n },\n {\n \"factoryPid\": \"org.eclipse.kura.cloud.subscriber.CloudSubscriber\",\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloud.CloudService\"\n },\n {\n \"factoryPid\": \"org.eclipse.kura.cloud.publisher.CloudPublisher\",\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloud.CloudService\"\n },\n {\n \"factoryPid\": \"org.eclipse.kura.cloudconnection.raw.mqtt.publisher.RawMqttPublisher\",\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint\"\n },\n {\n \"factoryPid\": \"org.eclipse.kura.event.publisher.EventPublisher\",\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloud.CloudService\"\n }\n ]\n}\n
For cloudConnectionFactories
elements:
cloudConnectionFactoryPid
: the PID of the cloud connection factorydefaultCloudEndpointPid
: If set, it represents the default PID for an instance of a new component suggested by the factory. This can be used by an user interface as a suggestion/placeholder for the name of a new cloud endpoint.cloudEndpointPidRegex
: If set, its value represents a regular expression that the PID of a new component must match.For pubSubFactories
elements:
factoryPid
: The factory PID of the publisher/subscripter component. It identifies the component type. It can be used for example to create a new component using the pubSub
POST method.cloudConnectionFactoryPid
: Specifies the cloudConnectionFactoryPid
of the CloudConnectionFactory associated with this component. Each publisher/subscriber component is only compatible with CloudEndpoint instances created by the factory having this cloudConnectionFactoryPid
.defaultPid
: If set, it represents the default PID for an instance of a new component suggested by the factory. This can be used by an user interface as a suggestion/placeholder for the name of a new publisher/subscriber.defaultPidRegex
: If set, its value represents a regular expression that the PID of a new component must match.
500 Internal Server error
services/cloudconnection/v1/cloudEndpoint/stackComponentPids
{\n \"cloudConnectionFactoryPid\" : \"org.eclipse.kura.cloud.CloudService\",\n \"cloudEndpointPid\": \"org.eclipse.kura.cloud.CloudService\"\n}\n
"},{"location":"references/rest-apis/rest-cloudconnection-api/#responses_2","title":"Responses","text":"{\n \"pids\": [\n \"org.eclipse.kura.cloud.CloudService\",\n \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\",\n \"org.eclipse.kura.data.DataService\"\n ]\n}\n
cloudConnectionFactoryPid
or cloudEndpointPid
are not foundcloudEndpointPid
and optionally other associated stack components, for example CloudService, DataService, DataTransportService.services/cloudconnection/v1/cloudEndpoint
{\n \"cloudConnectionFactoryPid\" : \"org.eclipse.kura.cloud.CloudService\",\n \"cloudEndpointPid\" : \"org.eclipse.kura.cloud.CloudService-1\"\n}\n
cloudEndpointPid
: The cloudEndpointPid
of the new instance that will be created. If the associated factory specifies the cloudEndpointPidRegex
property, this parameter must match the provided regex.cloudConnectionFactoryPid
: The cloudConnectionFactoryPid
of the factory that should be used to create the new component.cloudConnectionFactoryPid
or cloudEndpointPid
.cloudConnectionFactoryPid
services/cloudconnection/v1/pubSub
{\n \"pid\" : \"testPub\",\n \"factoryPid\" : \"org.eclipse.kura.cloud.publisher.CloudPublisher\",\n \"cloudEndpointPid\" : \"org.eclipse.kura.cloud.CloudService\"\n}\n
pid
: The PID of the new publisher/subscriber component. If the publisher/subscriber factory specifies the defaultPidRegex
property, this parameter must match the provided regex.factoryPid
: The factoryPid
of the publisher/subscriber factory.cloudEndpointPid
: The PID of the CloudEndpoint that the new publisher/subscriber component will be associated with. The associated CloudEndpoint must have been created by the CloudConnectionFactory with the cloudConnectionFactoryPid
specified by the publisher/subscriber factory.pid
, factoryPid
or cloudEndpointPid
factoryPid
or cloudEndpointPid
are wrong.cloudEndpoint/stackComponentPids
method.services/cloudconnection/v1/configurations
{\n \"pids\" : [\"testPub\", \"org.eclipse.kura.cloud.CloudService\"]\n}\n
"},{"location":"references/rest-apis/rest-cloudconnection-api/#responses_5","title":"Responses","text":"{\n \"configs\": [\n {\n \"pid\": \"testPub\",\n \"definition\": {\n \"ad\": [\n {\n \"name\": \"Application Id\",\n \"description\": \"The application id used to publish messages.\",\n \"id\": \"appId\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"W1\",\n \"isRequired\": true\n },\n {\n \"name\": \"Application Topic\",\n \"description\": \"Follows the application Id and specifies the rest of the publishing topic. Wildcards can be defined in the topic by specifing a $value in the field. The publisher will try to match \\\"value\\\" with a corresponding property in the received KuraMessage. If possible, the $value placeholder will be substituted with the real value specified in the KuraMessage received from the user application.\",\n \"id\": \"app.topic\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"A1/$assetName\",\n \"isRequired\": false\n },\n {\n \"option\": [\n {\n \"label\": \"0\",\n \"value\": \"0\"\n },\n {\n \"label\": \"1\",\n \"value\": \"1\"\n }\n ],\n \"name\": \"Qos\",\n \"description\": \"The desired quality of service for the messages that have to be published. If Qos is 0, the message is delivered at most once, or it is not delivered at all. If Qos is set to 1, the message is always delivered at least once.\",\n \"id\": \"qos\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"defaultValue\": \"0\",\n \"isRequired\": true\n },\n {\n \"name\": \"Retain\",\n \"description\": \"Default retaing flag for the published messages.\",\n \"id\": \"retain\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"defaultValue\": \"false\",\n \"isRequired\": true\n },\n {\n \"option\": [\n {\n \"label\": \"Data\",\n \"value\": \"data\"\n },\n {\n \"label\": \"Control\",\n \"value\": \"control\"\n }\n ],\n \"name\": \"Kind of Message\",\n \"description\": \"Type of message to be published.\",\n \"id\": \"message.type\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"data\",\n \"isRequired\": true\n },\n {\n \"name\": \"Priority\",\n \"description\": \"Message priority. Priority level 0 (highest) should be used sparingly and reserved for messages that should be sent with the minimum latency. Default is set to 7.\",\n \"id\": \"priority\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"0\",\n \"defaultValue\": \"7\",\n \"isRequired\": true\n }\n ],\n \"name\": \"CloudPublisher\",\n \"description\": \"The CloudPublisher allows to define publishing parameters and provide a simple endpoint where the applications can attach to publish their messages.\",\n \"id\": \"org.eclipse.kura.cloud.publisher.CloudPublisher\"\n },\n \"properties\": {\n \"app.topic\": {\n \"value\": \"A1/$assetName\",\n \"type\": \"STRING\"\n },\n \"message.type\": {\n \"value\": \"data\",\n \"type\": \"STRING\"\n },\n \"qos\": {\n \"value\": 0,\n \"type\": \"INTEGER\"\n },\n \"appId\": {\n \"value\": \"W1\",\n \"type\": \"STRING\"\n },\n \"retain\": {\n \"value\": false,\n \"type\": \"BOOLEAN\"\n },\n \"priority\": {\n \"value\": 7,\n \"type\": \"INTEGER\"\n },\n \"service.factoryPid\": {\n \"value\": \"org.eclipse.kura.cloud.publisher.CloudPublisher\",\n \"type\": \"STRING\"\n },\n \"cloud.endpoint.service.pid\": {\n \"value\": \"org.eclipse.kura.cloud.CloudService\",\n \"type\": \"STRING\"\n },\n \"kura.service.pid\": {\n \"value\": \"testPub\",\n \"type\": \"STRING\"\n },\n \"service.pid\": {\n \"value\": \"org.eclipse.kura.cloud.publisher.CloudPublisher-1699623980455-20\",\n \"type\": \"STRING\"\n }\n }\n },\n {\n \"pid\": \"org.eclipse.kura.cloud.CloudService\",\n \"definition\": {\n \"ad\": [\n {\n \"option\": [\n {\n \"label\": \"Set display name as device name\",\n \"value\": \"device-name\"\n },\n {\n \"label\": \"Set display name from hostname\",\n \"value\": \"hostname\"\n },\n {\n \"label\": \"Custom\",\n \"value\": \"custom\"\n },\n {\n \"label\": \"Server defined\",\n \"value\": \"server\"\n }\n ],\n \"name\": \"Device Display-Name\",\n \"description\": \"Friendly name of the device. Device name is the common name of the device (eg: Reliagate 20-25, Raspberry Pi, etc.). Hostname will use the linux hostname utility. Custom allows for defining a unique string. Server defined relies on the remote management server to define a name.\",\n \"id\": \"device.display-name\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"device-name\",\n \"isRequired\": true\n },\n {\n \"name\": \"Device Custom-Name\",\n \"description\": \"Custom name for the device. This value is applied ONLY if device.display-name is set to \\\"Custom\\\"\",\n \"id\": \"device.custom-name\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"isRequired\": false\n },\n {\n \"name\": \"Topic Control-Prefix\",\n \"description\": \"Topic prefix for system and device management messages.\",\n \"id\": \"topic.control-prefix\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"$EDC\",\n \"isRequired\": true\n },\n {\n \"name\": \"Encode gzip\",\n \"description\": \"Compress message payloads before sending them to the remote server to reduce the network traffic.\",\n \"id\": \"encode.gzip\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"defaultValue\": \"true\",\n \"isRequired\": false\n },\n {\n \"name\": \"Republish Mqtt Birth Cert On Gps Lock\",\n \"description\": \"Whether or not to republish the MQTT Birth Certificate on GPS lock event\",\n \"id\": \"republish.mqtt.birth.cert.on.gps.lock\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"defaultValue\": \"false\",\n \"isRequired\": true\n },\n {\n \"name\": \"Republish Mqtt Birth Cert On Modem Detect\",\n \"description\": \"Whether or not to republish the MQTT Birth Certificate on modem detection event\",\n \"id\": \"republish.mqtt.birth.cert.on.modem.detect\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"defaultValue\": \"false\",\n \"isRequired\": true\n },\n {\n \"name\": \"Republish Mqtt Birth Cert On Tamper Event\",\n \"description\": \"Whether or not to republish the MQTT Birth Certificate on a tamper event. This has effect only if a TamperDetectionService is available in the framework.\",\n \"id\": \"republish.mqtt.birth.cert.on.tamper.event\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"defaultValue\": \"true\",\n \"isRequired\": true\n },\n {\n \"name\": \"Enable Default Subscriptions\",\n \"description\": \"Manages the default subscriptions to the gateway management MQTT topics. When disabled, the gateway will not be remotely manageable.\",\n \"id\": \"enable.default.subscriptions\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"defaultValue\": \"true\",\n \"isRequired\": true\n },\n {\n \"option\": [\n {\n \"label\": \"Kura Protobuf\",\n \"value\": \"kura-protobuf\"\n },\n {\n \"label\": \"Simple JSON\",\n \"value\": \"simple-json\"\n }\n ],\n \"name\": \"Payload Encoding\",\n \"description\": \"Specify the message payload encoding.\",\n \"id\": \"payload.encoding\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"kura-protobuf\",\n \"isRequired\": true\n }\n ],\n \"icon\": [\n {\n \"resource\": \"CloudService\",\n \"size\": 32\n }\n ],\n \"name\": \"CloudService\",\n \"description\": \"The CloudService allows for setting a user friendly name for the current device. It also provides the option to compress message payloads to reduce network traffic.\",\n \"id\": \"org.eclipse.kura.cloud.CloudService\"\n },\n \"properties\": {\n \"topic.control-prefix\": {\n \"value\": \"$EDC\",\n \"type\": \"STRING\"\n },\n \"republish.mqtt.birth.cert.on.tamper.event\": {\n \"value\": true,\n \"type\": \"BOOLEAN\"\n },\n \"device.custom-name\": {\n \"value\": \"Intel UP\u00b2\",\n \"type\": \"STRING\"\n },\n \"device.display-name\": {\n \"value\": \"device-name\",\n \"type\": \"STRING\"\n },\n \"payload.encoding\": {\n \"value\": \"kura-protobuf\",\n \"type\": \"STRING\"\n },\n \"republish.mqtt.birth.cert.on.modem.detect\": {\n \"value\": false,\n \"type\": \"BOOLEAN\"\n },\n \"service.factoryPid\": {\n \"value\": \"org.eclipse.kura.cloud.CloudService\",\n \"type\": \"STRING\"\n },\n \"kura.service.pid\": {\n \"value\": \"org.eclipse.kura.cloud.CloudService\",\n \"type\": \"STRING\"\n },\n \"service.pid\": {\n \"value\": \"org.eclipse.kura.cloud.CloudService-1699623980404-13\",\n \"type\": \"STRING\"\n },\n \"enable.default.subscriptions\": {\n \"value\": true,\n \"type\": \"BOOLEAN\"\n },\n \"republish.mqtt.birth.cert.on.gps.lock\": {\n \"value\": false,\n \"type\": \"BOOLEAN\"\n },\n \"encode.gzip\": {\n \"value\": true,\n \"type\": \"BOOLEAN\"\n },\n \"DataService.target\": {\n \"value\": \"(kura.service.pid=org.eclipse.kura.data.DataService)\",\n \"type\": \"STRING\"\n },\n \"kura.cloud.service.factory.pid\": {\n \"value\": \"org.eclipse.kura.core.cloud.factory.DefaultCloudServiceFactory\",\n \"type\": \"STRING\"\n }\n }\n }\n ]\n}\n
- 200 Status OK - 500 Internal Error"},{"location":"references/rest-apis/rest-cloudconnection-api/#connect-cloudendpoint","title":"Connect CloudEndpoint","text":"services/cloudconnection/v1/cloudEndpoint/connect
{\n \"cloudEndpointPid\" : \"org.eclipse.kura.cloud.CloudService\"\n}\n
"},{"location":"references/rest-apis/rest-cloudconnection-api/#responses_6","title":"Responses","text":"cloudEndpointPid
services/cloudconnection/v1/cloudEndpoint/disconnect
{\n \"cloudEndpointPid\" : \"org.eclipse.kura.cloud.CloudService\"\n}\n
"},{"location":"references/rest-apis/rest-cloudconnection-api/#responses_7","title":"Responses","text":"cloudEndpointPid
services/cloudconnection/v1/cloudEndpoint/isConnected
{\n \"cloudEndpointPid\" : \"org.eclipse.kura.cloud.CloudService\"\n}\n
"},{"location":"references/rest-apis/rest-cloudconnection-api/#responses_8","title":"Responses","text":"{\n \"connected\": false\n}\n
- 200 Status OK - 404 Wrong cloudEndpointPid
- 500 Internal Server Error"},{"location":"references/rest-apis/rest-cloudconnection-api/#put-methods","title":"PUT methods","text":""},{"location":"references/rest-apis/rest-cloudconnection-api/#update-cloudendpoint-stack-component-configurations","title":"Update CloudEndpoint stack component configurations","text":"cloudEndpoint/stackComponentPids
method.services/cloudconnection/v1/configurations
takeSnapshot
set to true o false to specify if the ConfigurationService must save a snapshot with the updated configuration.{\n \"configs\": [\n {\n \"pid\": \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\",\n \"properties\": {\n \"broker-url\": {\n \"type\": \"STRING\",\n \"value\": \"mqtt://mqtt.eclipseprojects.io:1883\"\n },\n \"topic.context.account-name\": {\n \"type\": \"STRING\",\n \"value\": \"account-name-testX2\"\n },\n \"username\": {\n \"type\": \"STRING\",\n \"value\": \"username\"\n },\n \"password\": {\n \"type\": \"PASSWORD\",\n \"value\": \"Placeholder\"\n },\n \"client-id\": {\n \"type\": \"STRING\",\n \"value\": \"\"\n },\n \"keep-alive\": {\n \"type\": \"INTEGER\",\n \"value\": 30\n },\n \"timeout\": {\n \"type\": \"INTEGER\",\n \"value\": 20\n },\n \"clean-session\": {\n \"type\": \"BOOLEAN\",\n \"value\": true\n },\n \"lwt.topic\": {\n \"type\": \"STRING\",\n \"value\": \"$EDC/#account-name/#client-id/MQTT/LWT\"\n },\n \"lwt.payload\": {\n \"type\": \"STRING\",\n \"value\": \"\"\n },\n \"lwt.qos\": {\n \"type\": \"INTEGER\",\n \"value\": 0\n },\n \"lwt.retain\": {\n \"type\": \"BOOLEAN\",\n \"value\": false\n },\n \"in-flight.persistence\": {\n \"type\": \"STRING\",\n \"value\": \"memory\"\n },\n \"protocol-version\": {\n \"type\": \"INTEGER\",\n \"value\": 4\n },\n \"SslManagerService.target\": {\n \"type\": \"STRING\",\n \"value\": \"(kura.service.pid=org.eclipse.kura.ssl.SslManagerService)\"\n }\n }\n }\n ],\n \"takeSnapshot\" : true\n}\n
"},{"location":"references/rest-apis/rest-cloudconnection-api/#responses_9","title":"Responses","text":"pid
is wrong or non existent.services/cloudconnection/v1/cloudEndpoint
{\n \"cloudConnectionFactoryPid\" : \"org.eclipse.kura.cloud.CloudService\",\n \"cloudEndpointPid\" : \"org.eclipse.kura.cloud.CloudService-1\"\n}\n
"},{"location":"references/rest-apis/rest-cloudconnection-api/#responses_10","title":"Responses","text":"cloudConnectionFactoryPid
or cloudEndpointPid
are not foundservices/cloudconnection/v1/pubSub
{\n \"pid\" : \"testPub\"\n}\n
"},{"location":"references/rest-apis/rest-cloudconnection-api/#responses_11","title":"Responses","text":"cloudConnectionFactoryPid
or cloudEndpointPid
./services/command/v1/command/
{\n //Command to be executed on gateway\n \"command\":\"printenv TextEnvVarName1\",\n\n //Service Password for command Service\n \"password\":\"s3curePassw0rd\",\n\n //String base64 encoding of a zip file to transfer to gateway\n \"zipBytes\": \"UEsDBAoACAAAAIyD1lYAA AAAAAAAAAAAAAAJACAAdGVzdGZpbGUxVVQNAAfprpRk6a6UZOmulGR1eAsAAQT1AQAABBQAAABQSwcIAAAAAAAAAAAAAAAAUEsBAgoDCgAIAAAAjIPWVgAAAAAAAAAAAAAAAAkAIAAAAAAAAAAAAKSBAAAAAHRlc3RmaWxlMVVUDQAH6a6UZOmulGTprpRkdXgLAAEE9QEAAAQUAAAAUEsFBgAAAAABAAEAVwAAAFcAAAAAAA==\",\n\n //Command argument String array\n \"arguments\":[\"arg 1\"],\n\n //Shell environment Pairs Map\n \"environmentPairs\": \n {\n \"TextEnvVarName1\":\"TextEnvVarValue1\",\n \"TextEnvVarName2\":\"TextEnvVarValue2\"\n },\n //Working directory of command to be executed\n \"workingDirectory\":\"/tmp\",\n\n}\n
"},{"location":"references/rest-apis/rest-command-api/#responses","title":"Responses","text":"{\n \"stdout\": \"Command error output is displayed in this field\",\n \"stderr\": \"Command output is displayed in this field\",\n \"exitCode\": 0,\n \"isTimeOut\": false\n}\n
/services/command/v1/command/async
{\n //Command to be executed on gateway\n \"command\":\"printenv TextEnvVarName1\",\n\n //Service Password for command Service\n \"password\":\"s3curePassw0rd\",\n\n //String base64 encoding of a zip file to transfer to gateway\n \"zipBytes\": \"UEsDBAoACAAAAIyD1lYAA AAAAAAAAAAAAAAJACAAdGVzdGZpbGUxVVQNAAfprpRk6a6UZOmulGR1eAsAAQT1AQAABBQAAABQSwcIAAAAAAAAAAAAAAAAUEsBAgoDCgAIAAAAjIPWVgAAAAAAAAAAAAAAAAkAIAAAAAAAAAAAAKSBAAAAAHRlc3RmaWxlMVVUDQAH6a6UZOmulGTprpRkdXgLAAEE9QEAAAQUAAAAUEsFBgAAAAABAAEAVwAAAFcAAAAAAA==\",\n\n //Command argument String array\n \"arguments\":[\"arg 1\"],\n\n //Shell environment Pairs Map\n \"environmentPairs\": \n {\n \"TextEnvVarName1\":\"TextEnvVarValue1\",\n \"TextEnvVarName2\":\"TextEnvVarValue2\"\n },\n //Working directory of command to be executed\n \"workingDirectory\":\"/tmp\",\n\n}\n
"},{"location":"references/rest-apis/rest-command-api/#responses_1","title":"Responses","text":"Note
Use the following command to retrieve the base64 representation of a zip file. base64 -i <filename.zip>
This page describes the configuration V1 rest APIs.
"},{"location":"references/rest-apis/rest-configuration-service-v1/#rest-apis","title":"REST APIs","text":"The Configuration Service REST APIs are exposed by the org.eclipse.kura.rest.configuration
bundle, providing the following REST APIs under the /configuration/v1
path.
/factoryComponents
configuration JSON None The method lists all the FactoryComponents Pids tracked by the ConfigurationService POST /factoryComponents
configuration JSON FactoryComponentConfiguration object Creates a new ConfigurableComponent instance by creating a new configuration from a Configuration Admin factory. The FactoryComponentConfiguration object passed as request parameter will provide all the information needed to generate the instance. It links the factory Pid to be used, the target instance Pid, the properties to be used when creating the instance, and if the request should be persisted with a snapshot DELETE /factoryComponents/{pid}?takeSnapshot={takeSnapshot}
configuration JSON pid
= A String representing the pid of the instance generated by a Factory Component that needs to deleted; takeSnapshot
= an optional (default false) boolean to specify if a new snapshot needs to be created after the delete operation For the specified Pid and optional takeSnapshot query parameter, the ConfigurationService instance will delete the corresponding ConfigurableComponent instance GET /configurableComponents
configuration JSON None Lists the tracked configurable component Pids GET /configurableComponents/configurations
configuration JSON None Lists all the component configurations of all the ConfigurableComponents tracked by the ConfigurationService GET /configurableComponents/configurations/byFilter/{filter}
configuration JSON filter
= A String representing an OSGi filter. Lists the component configurations of all the ConfigurableComponents tracked by the ConfigurationService that match the filter specified GET /configurableComponents/configurations/byPid/{pid}
configuration JSON pid
= A String representing the pid of a configurable component instance Provides the ComponentConfiguration of the ConfigurableComponent matching the specified Pid GET /configurableComponents/configurations/byPid/{pid}/_default
configuration JSON pid
= A String representing the pid of a configurable component instance Provides the default Component Configuration for the component identified by the specified Pid POST /configurableComponents/configurations/byPid/{pid}/_update
configuration JSON pid
= A String representing the pid of a configurable component instance; ComponentConfigurationUpdateRequest
= the updated configuration provided in the request body Allows to update the component configuration identified by the provided PID POST /configurableComponents/configurations/_update
configuration JSON componentConfigurations
= the list of updated configurations provided in the request body Allows to update the configuration of multiple configurable components GET /snapshots
configuration JSON None Lists all the available snapshot IDs managed by the framework GET /snapshots/{id}
configuration JSON id
= the snapshot Id Returns the content of a given snapshot tracked by the framework POST /snapshots/_write
configuration JSON None Triggers the framework to take and persist a snapshot POST /snapshots/_rollback
configuration JSON None Rollbacks the framework to the last saved snapshot if available. POST /snapshots/{id}/_rollback
configuration JSON id
= the snapshot Id Rollbacks the framework to the snapshot identified by the provided ID POST /snapshots/_upload
configuration Consumes: XML Framework snapshot in XML form provided in the request body Uploads a snapshot. The framework will update the component(s) configuration accordingly to the configurations received"},{"location":"references/rest-apis/rest-configuration-service-v1/#get-all-the-factory-components-pids","title":"Get all the factory components pids","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/factoryComponents
Response:
[\n \"org.eclipse.kura.wire.Conditional\",\n \"org.eclipse.kura.cloudconnection.raw.mqtt.publisher.RawMqttPublisher\",\n \"org.eclipse.kura.misc.cloudcat.CloudCat\",\n \"org.eclipse.kura.core.db.H2DbServer\",\n \"org.eclipse.kura.wire.Fifo\",\n \"org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint\",\n \"org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl\",\n \"org.eclipse.kura.cloud.publisher.CloudPublisher\",\n \"org.eclipse.kura.core.db.H2DbService\",\n \"org.eclipse.kura.wire.CloudSubscriber\",\n \"org.eclipse.kura.wire.RegexFilter\",\n \"org.eclipse.kura.wire.Logger\",\n \"org.eclipse.kura.wire.Timer\",\n \"com.eurotech.framework.log.manager.LogManager\",\n \"com.eurotech.framework.log.journald.wire.JournaldWireComponent\",\n \"org.eclipse.kura.cloudconnection.raw.mqtt.subscriber.RawMqttSubscriber\",\n \"org.eclipse.kura.cloud.subscriber.CloudSubscriber\",\n \"org.eclipse.kura.ssl.SslManagerService\",\n \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\",\n \"com.eurotech.framework.log.journald.JournaldLogReader\",\n \"org.eclipse.kura.provisioning.ProvisioningService\",\n \"org.eclipse.kura.wire.CloudPublisher\",\n \"org.eclipse.kura.wire.H2DbWireRecordFilter\",\n \"org.eclipse.kura.cloud.CloudService\",\n \"org.eclipse.kura.data.DataService\",\n \"org.eclipse.kura.wire.H2DbWireRecordStore\",\n \"org.eclipse.kura.wire.Join\",\n \"com.eurotech.framework.log.publisher.LogPublisher\"\n]\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#create-component-from-factory","title":"Create component from factory","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/factoryComponents
Request body:
{\n \"factoryPid\": \"org.eclipse.kura.core.db.H2DbServer\",\n \"pid\": \"myH2DbServer\",\n \"properties\" : [],\n \"takeSnapshot\" : false\n}\n
The request must be provided with the following elements:
Request: URL - https://<gateway-ip>/services/configuration/v1/factoryComponents/{pid}?takeSnapshot={takeSnapshot}
Request: URL - https://<gateway-ip>/services/configuration/v1/configurableComponents
Response:
[\n \"org.eclipse.kura.clock.ClockService\",\n \"org.eclipse.kura.net.admin.NetworkConfigurationService\",\n \"org.eclipse.kura.position.PositionService\",\n \"com.eurotech.framework.internal.ansible.provider.AnsibleServiceImpl\",\n \"org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl\",\n \"com.eurotech.framework.internal.ansible.cloud.AnsibleActivityHandler\",\n \"default.diagnostic.publisher\",\n \"org.eclipse.kura.net.admin.FirewallConfigurationService\",\n \"com.eurotech.framework.internal.fail2ban.Fail2BanConfigurator\",\n \"default.log.publisher\",\n \"org.eclipse.kura.wire.graph.WireGraphService\",\n \"com.eurotech.framework.internal.floodingprotection.FloodingProtectionConfigurator\",\n \"org.eclipse.kura.ssl.SslManagerService\",\n \"org.eclipse.kura.http.server.manager.HttpService\",\n \"org.eclipse.kura.cloud.app.command.CommandCloudApp\",\n \"default.ping.publisher\",\n \"org.eclipse.kura.db.H2DbService\",\n \"com.eurotech.framework.diagnostics.DiagnosticsService\",\n \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\",\n \"org.eclipse.kura.deployment.agent\",\n \"DMKeystore\",\n \"LogReaderJournald\",\n \"default.alert.publisher\",\n \"org.eclipse.kura.core.deployment.CloudDeploymentHandlerV2\",\n \"HttpsKeystore\",\n \"com.eurotech.framework.security.aide.AideTamperDetectionServiceConfigurator\",\n \"org.eclipse.kura.provisioning.ProvisioningService\",\n \"LogManagerAuth\",\n \"com.eurotech.framework.security.journald.fss.FssTamperDetectionServiceConfigurator\",\n \"org.eclipse.kura.watchdog.WatchdogService\",\n \"org.eclipse.kura.cloud.CloudService\",\n \"LogManagerActivity\",\n \"org.eclipse.kura.data.DataService\",\n \"LogManagerDefault\",\n \"org.eclipse.kura.web.Console\",\n \"SSLKeystore\",\n \"com.eurotech.framework.net.vpn.client.VpnClient\",\n \"org.eclipse.kura.internal.rest.provider.RestService\",\n \"com.eurotech.framework.reboot.RebootService\"\n]\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#lists-all-the-component-configurations-of-all-the-configurablecomponents","title":"Lists all the component configurations of all the ConfigurableComponents","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/configurableComponents/configurations
Response:
[\n {\n \"pid\": \"org.eclipse.kura.clock.ClockService\",\n \"definition\": {\n \"ad\": [\n {\n \"option\": [],\n \"name\": \"enabled\",\n \"description\": \"Whether or not to enable the ClockService\",\n \"id\": \"enabled\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"_default\": \"true\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.set.hwclock\",\n \"description\": \"Whether or not to sync the system hardware clock after the system time gets set\",\n \"id\": \"clock.set.hwclock\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"_default\": \"true\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [\n {\n \"label\": \"java-ntp\",\n \"value\": \"java-ntp\",\n \"otherAttributes\": {}\n },\n {\n \"label\": \"ntpd\",\n \"value\": \"ntpd\",\n \"otherAttributes\": {}\n },\n {\n \"label\": \"chrony-advanced\",\n \"value\": \"chrony-advanced\",\n \"otherAttributes\": {}\n }\n ],\n \"name\": \"clock.provider\",\n \"description\": \"Source for setting the system clock. Verify the availabiliy of the selected provider before activate it.\",\n \"id\": \"clock.provider\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"java-ntp\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.host\",\n \"description\": \"The hostname that provides the system time via NTP\",\n \"id\": \"clock.ntp.host\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"0.pool.ntp.org\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.port\",\n \"description\": \"The port number that provides the system time via NTP\",\n \"id\": \"clock.ntp.port\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1\",\n \"max\": \"65535\",\n \"_default\": \"123\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.timeout\",\n \"description\": \"The NTP timeout in milliseconds\",\n \"id\": \"clock.ntp.timeout\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1000\",\n \"_default\": \"10000\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.max-retry\",\n \"description\": \"The maximum number of retries for the initial synchronization (with interval clock.ntp.retry.interval). If set to 0 the service will retry forever.\",\n \"id\": \"clock.ntp.max-retry\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"0\",\n \"_default\": \"0\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.retry.interval\",\n \"description\": \"When sync fails, interval in seconds between each retry.\",\n \"id\": \"clock.ntp.retry.interval\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1\",\n \"_default\": \"5\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.refresh-interval\",\n \"description\": \"Whether or not to sync the clock and if so, the frequency in seconds. If less than zero - no update, if equal to zero - sync once at startup, if greater than zero - the frequency in seconds to perform a new clock sync\",\n \"id\": \"clock.ntp.refresh-interval\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"_default\": \"3600\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"RTC File Name\",\n \"description\": \"The RTC File Name. It defaults to /dev/rtc0. This option is not used if chrony-advanced option is selected in clock.provider.\",\n \"id\": \"rtc.filename\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"/dev/rtc0\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"Chrony Configuration\",\n \"description\": \"Chrony configuration file.|TextArea\",\n \"id\": \"chrony.advanced.config\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"required\": false,\n \"otherAttributes\": {}\n }\n ],\n \"icon\": [\n {\n \"resource\": \"ClockService\",\n \"size\": 32,\n \"otherAttributes\": {}\n }\n ],\n \"name\": \"ClockService\",\n \"description\": \"ClockService Configuration\",\n \"id\": \"org.eclipse.kura.clock.ClockService\",\n \"otherAttributes\": {}\n },\n \"properties\": {\n \"clock.ntp.host\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"0.pool.ntp.org\"\n },\n \"clock.ntp.max-retry\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 0\n },\n \"clock.set.hwclock\": {\n \"array\": false,\n \"type\": \"Boolean\",\n \"value\": true\n },\n \"clock.ntp.timeout\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 10000\n },\n \"enabled\": {\n \"array\": false,\n \"type\": \"Boolean\",\n \"value\": false\n },\n \"clock.ntp.retry.interval\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 5\n },\n \"kura.service.pid\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"org.eclipse.kura.clock.ClockService\"\n },\n \"service.pid\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"org.eclipse.kura.clock.ClockService\"\n },\n \"clock.ntp.port\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 123\n },\n \"clock.provider\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"java-ntp\"\n },\n \"clock.ntp.refresh-interval\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 3600\n },\n \"rtc.filename\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"/dev/rtc1\"\n },\n \"chrony.advanced.config\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"\"\n }\n }\n },\n ...\n]\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#list-the-configurations-of-all-the-configurablecomponents-that-match-a-filter","title":"List the configurations of all the ConfigurableComponents that match a filter","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/configurableComponents/configurations/byFilter/(service.pid=org.eclipse.kura.clock.ClockService)
Response:
[\n {\n \"pid\": \"org.eclipse.kura.clock.ClockService\",\n \"definition\": {\n \"ad\": [\n {\n \"option\": [],\n \"name\": \"enabled\",\n \"description\": \"Whether or not to enable the ClockService\",\n \"id\": \"enabled\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"_default\": \"true\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.set.hwclock\",\n \"description\": \"Whether or not to sync the system hardware clock after the system time gets set\",\n \"id\": \"clock.set.hwclock\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"_default\": \"true\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [\n {\n \"label\": \"java-ntp\",\n \"value\": \"java-ntp\",\n \"otherAttributes\": {}\n },\n {\n \"label\": \"ntpd\",\n \"value\": \"ntpd\",\n \"otherAttributes\": {}\n },\n {\n \"label\": \"chrony-advanced\",\n \"value\": \"chrony-advanced\",\n \"otherAttributes\": {}\n }\n ],\n \"name\": \"clock.provider\",\n \"description\": \"Source for setting the system clock. Verify the availabiliy of the selected provider before activate it.\",\n \"id\": \"clock.provider\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"java-ntp\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.host\",\n \"description\": \"The hostname that provides the system time via NTP\",\n \"id\": \"clock.ntp.host\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"0.pool.ntp.org\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.port\",\n \"description\": \"The port number that provides the system time via NTP\",\n \"id\": \"clock.ntp.port\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1\",\n \"max\": \"65535\",\n \"_default\": \"123\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.timeout\",\n \"description\": \"The NTP timeout in milliseconds\",\n \"id\": \"clock.ntp.timeout\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1000\",\n \"_default\": \"10000\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.max-retry\",\n \"description\": \"The maximum number of retries for the initial synchronization (with interval clock.ntp.retry.interval). If set to 0 the service will retry forever.\",\n \"id\": \"clock.ntp.max-retry\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"0\",\n \"_default\": \"0\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.retry.interval\",\n \"description\": \"When sync fails, interval in seconds between each retry.\",\n \"id\": \"clock.ntp.retry.interval\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1\",\n \"_default\": \"5\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.refresh-interval\",\n \"description\": \"Whether or not to sync the clock and if so, the frequency in seconds. If less than zero - no update, if equal to zero - sync once at startup, if greater than zero - the frequency in seconds to perform a new clock sync\",\n \"id\": \"clock.ntp.refresh-interval\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"_default\": \"3600\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"RTC File Name\",\n \"description\": \"The RTC File Name. It defaults to /dev/rtc0. This option is not used if chrony-advanced option is selected in clock.provider.\",\n \"id\": \"rtc.filename\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"/dev/rtc0\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"Chrony Configuration\",\n \"description\": \"Chrony configuration file.|TextArea\",\n \"id\": \"chrony.advanced.config\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"required\": false,\n \"otherAttributes\": {}\n }\n ],\n \"icon\": [\n {\n \"resource\": \"ClockService\",\n \"size\": 32,\n \"otherAttributes\": {}\n }\n ],\n \"name\": \"ClockService\",\n \"description\": \"ClockService Configuration\",\n \"id\": \"org.eclipse.kura.clock.ClockService\",\n \"otherAttributes\": {}\n },\n \"properties\": {\n \"clock.ntp.host\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"0.pool.ntp.org\"\n },\n \"clock.ntp.max-retry\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 0\n },\n \"clock.set.hwclock\": {\n \"array\": false,\n \"type\": \"Boolean\",\n \"value\": true\n },\n \"clock.ntp.timeout\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 10000\n },\n \"enabled\": {\n \"array\": false,\n \"type\": \"Boolean\",\n \"value\": false\n },\n \"clock.ntp.retry.interval\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 5\n },\n \"kura.service.pid\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"org.eclipse.kura.clock.ClockService\"\n },\n \"service.pid\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"org.eclipse.kura.clock.ClockService\"\n },\n \"clock.ntp.port\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 123\n },\n \"clock.provider\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"java-ntp\"\n },\n \"clock.ntp.refresh-interval\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 3600\n },\n \"rtc.filename\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"/dev/rtc1\"\n },\n \"chrony.advanced.config\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"\"\n }\n }\n }\n]\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#get-the-configuration-of-the-configurablecomponent-matching-a-pid","title":"Get the configuration of the ConfigurableComponent matching a pid","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/configurableComponents/configurations/byPid/org.eclipse.kura.clock.ClockService
Response:
{\n \"pid\": \"org.eclipse.kura.clock.ClockService\",\n \"definition\": {\n \"ad\": [\n {\n \"option\": [],\n \"name\": \"enabled\",\n \"description\": \"Whether or not to enable the ClockService\",\n \"id\": \"enabled\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"_default\": \"true\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.set.hwclock\",\n \"description\": \"Whether or not to sync the system hardware clock after the system time gets set\",\n \"id\": \"clock.set.hwclock\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"_default\": \"true\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [\n {\n \"label\": \"java-ntp\",\n \"value\": \"java-ntp\",\n \"otherAttributes\": {}\n },\n {\n \"label\": \"ntpd\",\n \"value\": \"ntpd\",\n \"otherAttributes\": {}\n },\n {\n \"label\": \"chrony-advanced\",\n \"value\": \"chrony-advanced\",\n \"otherAttributes\": {}\n }\n ],\n \"name\": \"clock.provider\",\n \"description\": \"Source for setting the system clock. Verify the availabiliy of the selected provider before activate it.\",\n \"id\": \"clock.provider\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"java-ntp\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.host\",\n \"description\": \"The hostname that provides the system time via NTP\",\n \"id\": \"clock.ntp.host\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"0.pool.ntp.org\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.port\",\n \"description\": \"The port number that provides the system time via NTP\",\n \"id\": \"clock.ntp.port\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1\",\n \"max\": \"65535\",\n \"_default\": \"123\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.timeout\",\n \"description\": \"The NTP timeout in milliseconds\",\n \"id\": \"clock.ntp.timeout\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1000\",\n \"_default\": \"10000\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.max-retry\",\n \"description\": \"The maximum number of retries for the initial synchronization (with interval clock.ntp.retry.interval). If set to 0 the service will retry forever.\",\n \"id\": \"clock.ntp.max-retry\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"0\",\n \"_default\": \"0\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.retry.interval\",\n \"description\": \"When sync fails, interval in seconds between each retry.\",\n \"id\": \"clock.ntp.retry.interval\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1\",\n \"_default\": \"5\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.refresh-interval\",\n \"description\": \"Whether or not to sync the clock and if so, the frequency in seconds. If less than zero - no update, if equal to zero - sync once at startup, if greater than zero - the frequency in seconds to perform a new clock sync\",\n \"id\": \"clock.ntp.refresh-interval\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"_default\": \"3600\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"RTC File Name\",\n \"description\": \"The RTC File Name. It defaults to /dev/rtc0. This option is not used if chrony-advanced option is selected in clock.provider.\",\n \"id\": \"rtc.filename\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"/dev/rtc0\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"Chrony Configuration\",\n \"description\": \"Chrony configuration file.|TextArea\",\n \"id\": \"chrony.advanced.config\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"required\": false,\n \"otherAttributes\": {}\n }\n ],\n \"icon\": [\n {\n \"resource\": \"ClockService\",\n \"size\": 32,\n \"otherAttributes\": {}\n }\n ],\n \"name\": \"ClockService\",\n \"description\": \"ClockService Configuration\",\n \"id\": \"org.eclipse.kura.clock.ClockService\",\n \"otherAttributes\": {}\n },\n \"properties\": {\n \"clock.ntp.host\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"0.pool.ntp.org\"\n },\n \"clock.ntp.max-retry\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 0\n },\n \"clock.set.hwclock\": {\n \"array\": false,\n \"type\": \"Boolean\",\n \"value\": true\n },\n \"clock.ntp.timeout\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 10000\n },\n \"enabled\": {\n \"array\": false,\n \"type\": \"Boolean\",\n \"value\": false\n },\n \"clock.ntp.retry.interval\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 5\n },\n \"kura.service.pid\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"org.eclipse.kura.clock.ClockService\"\n },\n \"service.pid\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"org.eclipse.kura.clock.ClockService\"\n },\n \"clock.ntp.port\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 123\n },\n \"clock.provider\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"java-ntp\"\n },\n \"clock.ntp.refresh-interval\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 3600\n },\n \"rtc.filename\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"/dev/rtc1\"\n },\n \"chrony.advanced.config\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"\"\n }\n }\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#get-the-default-configuration-of-the-configurablecomponent-matching-a-pid","title":"Get the default configuration of the ConfigurableComponent matching a pid","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/configurableComponents/configurations/byPid/org.eclipse.kura.clock.ClockService/_default
Response:
{\n \"pid\": \"org.eclipse.kura.clock.ClockService\",\n \"definition\": {\n \"ad\": [\n {\n \"option\": [],\n \"name\": \"enabled\",\n \"description\": \"Whether or not to enable the ClockService\",\n \"id\": \"enabled\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"_default\": \"true\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.set.hwclock\",\n \"description\": \"Whether or not to sync the system hardware clock after the system time gets set\",\n \"id\": \"clock.set.hwclock\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"_default\": \"true\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [\n {\n \"label\": \"java-ntp\",\n \"value\": \"java-ntp\",\n \"otherAttributes\": {}\n },\n {\n \"label\": \"ntpd\",\n \"value\": \"ntpd\",\n \"otherAttributes\": {}\n },\n {\n \"label\": \"chrony-advanced\",\n \"value\": \"chrony-advanced\",\n \"otherAttributes\": {}\n }\n ],\n \"name\": \"clock.provider\",\n \"description\": \"Source for setting the system clock. Verify the availabiliy of the selected provider before activate it.\",\n \"id\": \"clock.provider\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"java-ntp\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.host\",\n \"description\": \"The hostname that provides the system time via NTP\",\n \"id\": \"clock.ntp.host\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"0.pool.ntp.org\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.port\",\n \"description\": \"The port number that provides the system time via NTP\",\n \"id\": \"clock.ntp.port\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1\",\n \"max\": \"65535\",\n \"_default\": \"123\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.timeout\",\n \"description\": \"The NTP timeout in milliseconds\",\n \"id\": \"clock.ntp.timeout\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1000\",\n \"_default\": \"10000\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.max-retry\",\n \"description\": \"The maximum number of retries for the initial synchronization (with interval clock.ntp.retry.interval). If set to 0 the service will retry forever.\",\n \"id\": \"clock.ntp.max-retry\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"0\",\n \"_default\": \"0\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.retry.interval\",\n \"description\": \"When sync fails, interval in seconds between each retry.\",\n \"id\": \"clock.ntp.retry.interval\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1\",\n \"_default\": \"5\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.refresh-interval\",\n \"description\": \"Whether or not to sync the clock and if so, the frequency in seconds. If less than zero - no update, if equal to zero - sync once at startup, if greater than zero - the frequency in seconds to perform a new clock sync\",\n \"id\": \"clock.ntp.refresh-interval\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"_default\": \"3600\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"RTC File Name\",\n \"description\": \"The RTC File Name. It defaults to /dev/rtc0. This option is not used if chrony-advanced option is selected in clock.provider.\",\n \"id\": \"rtc.filename\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"/dev/rtc0\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"Chrony Configuration\",\n \"description\": \"Chrony configuration file.|TextArea\",\n \"id\": \"chrony.advanced.config\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"required\": false,\n \"otherAttributes\": {}\n }\n ],\n \"icon\": [\n {\n \"resource\": \"ClockService\",\n \"size\": 32,\n \"otherAttributes\": {}\n }\n ],\n \"name\": \"ClockService\",\n \"description\": \"ClockService Configuration\",\n \"id\": \"org.eclipse.kura.clock.ClockService\",\n \"otherAttributes\": {}\n },\n \"properties\": {\n \"clock.ntp.host\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"0.pool.ntp.org\"\n },\n \"clock.provider\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"java-ntp\"\n },\n \"clock.ntp.port\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 123\n },\n \"clock.ntp.max-retry\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 0\n },\n \"clock.ntp.refresh-interval\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 3600\n },\n \"rtc.filename\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"/dev/rtc0\"\n },\n \"clock.set.hwclock\": {\n \"array\": false,\n \"type\": \"Boolean\",\n \"value\": true\n },\n \"enabled\": {\n \"array\": false,\n \"type\": \"Boolean\",\n \"value\": true\n },\n \"clock.ntp.timeout\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 10000\n },\n \"clock.ntp.retry.interval\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 5\n }\n }\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#update-the-component-configuration-identified-matching-a-pid","title":"Update the component configuration identified matching a pid","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/configurableComponents/configurations/byPid/org.eclipse.kura.clock.ClockService/_update
Request body:
{\n \"takeSnapshot\":true,\n \"componentConfigurationRequest\": {\n \"properties\": {\n \"enabled\": {\n \"type\": \"boolean\",\n \"value\": false,\n \"array\": false\n }\n }\n }\n}\n
Warning
Every service may need a different set of parameters and combination of them to reach the desired result. For the NetworkAdminService, for example, the following configuration is required to disable a specific network interface (enp2s0) and prevent re-enabling at reboot. Please verify offline the REST APIs executed and the different deploying scenarios before distributing updates to the fleet of devices.
{\n \"takeSnapshot\":true,\n \"componentConfigurationRequest\": {\n \"properties\": {\n \"net.interface.enp2s0.config.ip4.status\": {\n \"type\": \"string\",\n \"value\": \"netIPv4StatusDisabled\",\n \"array\": false\n },\n \"net.interface.enp2s0.config.autoconnect\": {\n \"type\": \"boolean\",\n \"value\": false,\n \"array\": false\n }\n }\n }\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#update-the-configuration-of-multiple-configurable-components","title":"Update the configuration of multiple configurable components","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/configurableComponents/configurations/_update
Request body:
{\n \"takeSnapshot\": true,\n \"componentConfigurations\": [\n {\n \"pid\": \"org.eclipse.kura.clock.ClockService\",\n \"properties\": {\n \"enabled\": {\n \"type\": \"boolean\",\n \"value\": false,\n \"array\": false\n }\n }\n }\n ]\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#list-all-the-available-snapshot-ids","title":"List all the available snapshot IDs","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/snapshots
Response:
[\n 0,\n 1630930775789,\n 1630930776355,\n 1630930776839,\n 1630930797402,\n 1630930805305\n]\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#get-the-content-of-a-given-snapshot","title":"Get the content of a given snapshot","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/snapshots/{id}
Response:
[\n {\n \"pid\": \"org.eclipse.kura.clock.ClockService\",\n \"properties\": {\n \"clock.ntp.host\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"0.pool.ntp.org\"\n },\n \"clock.ntp.port\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 123\n },\n \"clock.provider\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"java-ntp\"\n },\n \"clock.ntp.max-retry\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 0\n },\n \"clock.ntp.refresh-interval\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 3600\n },\n \"rtc.filename\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"/dev/rtc1\"\n },\n \"clock.set.hwclock\": {\n \"array\": false,\n \"type\": \"Boolean\",\n \"value\": true\n },\n \"clock.ntp.timeout\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 10000\n },\n \"enabled\": {\n \"array\": false,\n \"type\": \"Boolean\",\n \"value\": true\n },\n \"clock.ntp.retry.interval\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 5\n },\n \"kura.service.pid\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"org.eclipse.kura.clock.ClockService\"\n },\n \"service.pid\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"org.eclipse.kura.clock.ClockService\"\n }\n }\n },\n ...\n]\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#trigger-the-framework-to-take-and-persist-a-snapshot","title":"Trigger the framework to take and persist a snapshot","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/snapshots/_write
Response:
1631095409516\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#rollbacks-to-the-snapshot-identified-by-the-provided-id","title":"Rollbacks to the snapshot identified by the provided ID","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/snapshots/_rollback
Response:
1631093011618\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#upload-a-snapshot-as-xml","title":"Upload a snapshot as XML","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/snapshots/_upload
Request body:
<?xml version=\"1.0\" encoding=\"UTF-8\"?><esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n <esf:configuration pid=\"org.eclipse.kura.clock.ClockService\">\n <esf:properties>\n <esf:property array=\"false\" encrypted=\"false\" name=\"clock.ntp.host\" type=\"String\">\n <esf:value>0.pool.ntp.org</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"clock.ntp.port\" type=\"Integer\">\n <esf:value>123</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"clock.provider\" type=\"String\">\n <esf:value>java-ntp</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"clock.ntp.max-retry\" type=\"Integer\">\n <esf:value>0</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"clock.ntp.refresh-interval\" type=\"Integer\">\n <esf:value>3600</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"rtc.filename\" type=\"String\">\n <esf:value>/dev/rtc1</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"clock.set.hwclock\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"clock.ntp.timeout\" type=\"Integer\">\n <esf:value>10000</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"enabled\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"clock.ntp.retry.interval\" type=\"Integer\">\n <esf:value>5</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"kura.service.pid\" type=\"String\">\n <esf:value>org.eclipse.kura.clock.ClockService</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"service.pid\" type=\"String\">\n <esf:value>org.eclipse.kura.clock.ClockService</esf:value>\n </esf:property>\n </esf:properties>\n </esf:configuration>\n</esf:configurations>\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/","title":"Configuration V2 REST APIs and CONF-V2 Request Handler","text":"This page describes the CONF-V2 request handler and configuration/v2
rest APIs. Accessing the REST APIs requires to use an identity with the rest.configuration
permission assigned.
/services/configuration/v2/snapshots
/services/configuration/v2/factoryComponents
/services/configuration/v2/factoryComponents
create:$pid
for component creation operations, where $pid
is the pid of the instance, and snapshot
, for the snapshot creation operation. In case of an unexpected failure, a generic error response will be returned.response body :
Variants:
/services/configuration/v2/factoryComponents/byPid
delete:$pid
for component delete operations, where $pid
is the pid of the instance, and snapshot
, for the snapshot creation operation. In case of an unexpected failure, a generic error response will be returned.response body :
Variants:
/services/configuration/v2/factoryComponents/ocd
pid
property of the received configurations will report the factory pid, the ocd
field will contain the definition, the properties
field will not be present./services/configuration/v2/factoryComponents/ocd/byFactoryPid
pid
property of the received configurations will report the factory pid, the ocd
field will contain the definition, the properties
field will not be present. If the OCD for a given factory pid cannot be found, it will not be included in the result./services/configuration/v2/configurableComponents
/services/configuration/v2/configurableComponents/pidsWithFactory
/services/configuration/v2/configurableComponents/configurations
pid
, ocd
and properties
./services/configuration/v2/configurableComponents/configurations/byPid
pid
, ocd
and properties
./services/configuration/v2/configurableComponents/configurations/byPid/_default
pid
, ocd
and properties
./services/configuration/v2/configurableComponents/configurations/_update
update:$pid
for component update operations, where $pid
is the pid of the instance, and snapshot
, for the snapshot creation operation. In case of an unexpected failure, a generic error response will be returned.response body :
Variants:
/services/configuration/v2/snapshots/_write
/services/configuration/v2/snapshots/_rollback
/services/configuration/v2/snapshots/byId/_rollback
Represents a set of pids with the corresponding factory pid. Properties:
components: array
The set of pids and factory pids
array elements: object
The pid and factory pid Properties:
pid: string
The component pid.
string
{\n \"components\": [\n {\n \"factoryPid\": \"org.eclipse.kura.core.db.H2DbService\",\n \"pid\": \"org.eclipse.kura.db.H2DbService\"\n },\n {\n \"factoryPid\": \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\",\n \"pid\": \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\"\n },\n {\n \"pid\": \"org.eclipse.kura.web.Console\"\n }\n ]\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#snapshotidset","title":"SnapshotIdSet","text":"An object decribing a set of configuration snapshot ids Properties:
array
The set of snapshot ids.number
A snapshot id.{\n \"ids\": [\n 0,\n 1638438049921,\n 1638438146960,\n 1638439710944,\n 1638439717931,\n 1638439734077,\n 1638439767252,\n 1638521986953,\n 1638521993692,\n 1638522572822\n ]\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#propertytype","title":"PropertyType","text":"A string that describes the type of a configuration property. * Possible values * STRING
* LONG
* DOUBLE
* FLOAT
* INTEGER
* BYTE
* CHAR
* BOOLEAN
* SHORT
* PASSWORD
\"STRING\"\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#configurationproperty","title":"ConfigurationProperty","text":"An object describing a configuration property. Properties:
string (enumerated)
variant
optional In requests, this field can be omitted or set to null
to assign the null
value to a non required configuration property. Describes the property value. The value type depends on the type property. Variants:
LONG
, DOUBLE
, FLOAT
, INTEGER
, BYTE
or SHORT
and the property does not represent an array.STRING
, PASSWORD
or CHAR
and the property is not an array. In case of CHAR
type, the value must have a length of 1.BOOLEAN
and the property is not an arrayLONG
, DOUBLE
, FLOAT
, INTEGER
, BYTE
or SHORT
and the property represents an array.number
The property values as numbers.STRING
, PASSWORD
or CHAR
and the property is an array.string
The property values as strings. In case of CHAR
type, the values must have a length of 1.BOOLEAN
and the property is an arraybool
The property values as booleans.{\n \"type\": \"STRING\",\n \"value\": \"foo\"\n}\n
{\n \"type\": \"STRING\",\n \"value\": [\n \"foo\",\n \"bar\"\n ]\n}\n
{\n \"type\": \"INTEGER\",\n \"value\": 12\n}\n
{\n \"type\": \"LONG\",\n \"value\": [\n 1,\n 2,\n 3,\n 4\n ]\n}\n
{\n \"type\": \"PASSWORD\",\n \"value\": \"myPassword\"\n}\n
{\n \"type\": \"PASSWORD\",\n \"value\": [\n \"my\",\n \"password\",\n \"array\"\n ]\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#configurationproperties","title":"ConfigurationProperties","text":"An object representing a set of configuration properties. The members of this object represent configuration property, the member names represent the configuration property ids. This object can have a variable number of members. Properties:
object
{\n \"KeystoreService.target\": {\n \"type\": \"STRING\",\n \"value\": \"(kura.service.pid=HttpsKeystore)\"\n },\n \"https.client.auth.ports\": {\n \"type\": \"INTEGER\",\n \"value\": [\n 4443\n ]\n },\n \"https.client.revocation.soft.fail\": {\n \"type\": \"BOOLEAN\",\n \"value\": false\n },\n \"https.ports\": {\n \"type\": \"INTEGER\",\n \"value\": [\n 443\n ]\n },\n \"https.revocation.check.enabled\": {\n \"type\": \"BOOLEAN\",\n \"value\": false\n },\n \"kura.service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.http.server.manager.HttpService\"\n },\n \"service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.http.server.manager.HttpService\"\n },\n \"ssl.revocation.mode\": {\n \"type\": \"STRING\",\n \"value\": \"PREFER_OCSP\"\n }\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#option","title":"Option","text":"An object describing an allowed element for a multi choiche field. Properties:
string
string
The option value encoded as a string.{\n \"label\": \"Value 1\",\n \"value\": \"1\"\n}\n
{\n \"value\": \"foo\"\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#attributedefinition","title":"AttributeDefinition","text":"A descriptor of a configuration property. Properties:
string
The id of the attribute definition. This field corresponds to the configuration property name.string (enumerated)
string
string
number
An integer describing the property cardinality. If the value is 0, then the property is a singleton value (not an array), if it is > 0, then the configuration property is an array and this property specifies the maximum allowed array length.string
string
bool
Specifies whether the configuration parameter is required or not.string
array
object
{\n \"defaultValue\": \"false\",\n \"description\": \"Specifies whether the DB server is enabled or not.\",\n \"id\": \"db.server.enabled\",\n \"isRequired\": true,\n \"name\": \"db.server.enabled\",\n \"type\": \"BOOLEAN\"\n}\n
{\n \"defaultValue\": \"TCP\",\n \"description\": \"Specifies the server type, see http://www.h2database.com/javadoc/org/h2/tools/Server.html for more details.\",\n \"id\": \"db.server.type\",\n \"isRequired\": true,\n \"name\": \"db.server.type\",\n \"option\": [\n {\n \"label\": \"WEB\",\n \"value\": \"WEB\"\n },\n {\n \"label\": \"TCP\",\n \"value\": \"TCP\"\n },\n {\n \"label\": \"PG\",\n \"value\": \"PG\"\n }\n ],\n \"type\": \"STRING\"\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#objectclassdefinition","title":"ObjectClassDefinition","text":"Provides some metadata information about a component configuration. Properties:
array
The metadata about the configuration properties.object
array
optional Can be missing if the OCD does not define icons. A list of icons that visually represent the configuration.
object
Properties:
string
An identifier of the icon image resource.number
The icon width and height in pixels.string
A user friendly name for the component configuration.string
A user friendly description of the component configuration.string
An identifier of the component configuration.{\n \"ad\": [\n {\n \"defaultValue\": \"false\",\n \"description\": \"The WatchdogService monitors CriticalComponents and reboots the system if one of them hangs. Once enabled the WatchdogService starts refreshing the watchdog device, which will reset the system if WatchdogService hangs.\",\n \"id\": \"enabled\",\n \"isRequired\": true,\n \"name\": \"Watchdog enable\",\n \"type\": \"BOOLEAN\"\n },\n {\n \"defaultValue\": \"10000\",\n \"description\": \"WatchdogService's refresh interval in ms of the Watchdog device. The value can be set between 1 and 60 seconds and should not be set to a value greater or equal to the Watchdog device's timeout value\",\n \"id\": \"pingInterval\",\n \"isRequired\": true,\n \"max\": \"60000\",\n \"name\": \"Watchdog refresh interval\",\n \"type\": \"INTEGER\"\n },\n {\n \"defaultValue\": \"/dev/watchdog\",\n \"description\": \"Watchdog device path e.g. /dev/watchdog.\",\n \"id\": \"watchdogDevice\",\n \"isRequired\": true,\n \"name\": \"Watchdog device path\",\n \"type\": \"STRING\"\n },\n {\n \"defaultValue\": \"/opt/eclipse/kura/data/kura-reboot-cause\",\n \"description\": \"The path for the file that will contain the reboot cause information.\",\n \"id\": \"rebootCauseFilePath\",\n \"isRequired\": true,\n \"name\": \"Reboot Cause File Path\",\n \"type\": \"STRING\"\n }\n ],\n \"description\": \"The WatchdogService handles the hardware watchdog of the platform. The parameter define the ping periodicity of the hardware watchdog to ensure it does not reboot. The WatchdogService will reset the watchdog timeout, can disable it (where supported) with the Magic Character, but cannot set the refresh rate of a watchdog device.\",\n \"icon\": [\n {\n \"resource\": \"WatchdogService\",\n \"size\": 32\n }\n ],\n \"id\": \"org.eclipse.kura.watchdog.WatchdogService\",\n \"name\": \"WatchdogService\"\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#componentconfiguration","title":"ComponentConfiguration","text":"Describes a component configuration. Properties:
string
The identifier of this configuration.object
object
{\n \"definition\": {\n \"ad\": [\n {\n \"cardinality\": 3,\n \"description\": \"If set to a non empty list, REST API access will be allowed only on the specified ports. If set to an empty list, access will be allowed on all ports. Please make sure that the allowed ports are open in HttpService and Firewall configuration.\",\n \"id\": \"allowed.ports\",\n \"isRequired\": false,\n \"max\": \"65535\",\n \"min\": \"1\",\n \"name\": \"Allowed ports\",\n \"type\": \"INTEGER\"\n }\n ],\n \"description\": \"This service allows to configure settings related to Kura REST APIs\",\n \"id\": \"org.eclipse.kura.internal.rest.provider.RestService\",\n \"name\": \"RestService\"\n },\n \"pid\": \"org.eclipse.kura.internal.rest.provider.RestService\",\n \"properties\": {\n \"kura.service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.internal.rest.provider.RestService\"\n },\n \"service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.internal.rest.provider.RestService\"\n }\n }\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#componentconfigurationlist","title":"ComponentConfigurationList","text":"Represents a list of component configurations. Properties:
array
The component configurationsobject
{\n \"configs\": [\n {\n \"definition\": {\n \"ad\": [\n {\n \"defaultValue\": \"true\",\n \"description\": \"Whether or not to enable the ClockService\",\n \"id\": \"enabled\",\n \"isRequired\": true,\n \"name\": \"enabled\",\n \"type\": \"BOOLEAN\"\n },\n {\n \"defaultValue\": \"true\",\n \"description\": \"Whether or not to sync the system hardware clock after the system time gets set\",\n \"id\": \"clock.set.hwclock\",\n \"isRequired\": true,\n \"name\": \"clock.set.hwclock\",\n \"type\": \"BOOLEAN\"\n },\n {\n \"defaultValue\": \"java-ntp\",\n \"description\": \"Source for setting the system clock. Verify the availabiliy of the selected provider before activate it.\",\n \"id\": \"clock.provider\",\n \"isRequired\": true,\n \"name\": \"clock.provider\",\n \"option\": [\n {\n \"label\": \"java-ntp\",\n \"value\": \"java-ntp\"\n },\n {\n \"label\": \"ntpd\",\n \"value\": \"ntpd\"\n },\n {\n \"label\": \"chrony-advanced\",\n \"value\": \"chrony-advanced\"\n }\n ],\n \"type\": \"STRING\"\n },\n {\n \"defaultValue\": \"0.pool.ntp.org\",\n \"description\": \"The hostname that provides the system time via NTP\",\n \"id\": \"clock.ntp.host\",\n \"isRequired\": true,\n \"name\": \"clock.ntp.host\",\n \"type\": \"STRING\"\n },\n {\n \"defaultValue\": \"123\",\n \"description\": \"The port number that provides the system time via NTP\",\n \"id\": \"clock.ntp.port\",\n \"isRequired\": true,\n \"max\": \"65535\",\n \"min\": \"1\",\n \"name\": \"clock.ntp.port\",\n \"type\": \"INTEGER\"\n },\n {\n \"defaultValue\": \"10000\",\n \"description\": \"The NTP timeout in milliseconds\",\n \"id\": \"clock.ntp.timeout\",\n \"isRequired\": true,\n \"min\": \"1000\",\n \"name\": \"clock.ntp.timeout\",\n \"type\": \"INTEGER\"\n },\n {\n \"defaultValue\": \"0\",\n \"description\": \"The maximum number of retries for the initial synchronization (with interval clock.ntp.retry.interval). If set to 0 the service will retry forever.\",\n \"id\": \"clock.ntp.max-retry\",\n \"isRequired\": true,\n \"min\": \"0\",\n \"name\": \"clock.ntp.max-retry\",\n \"type\": \"INTEGER\"\n },\n {\n \"defaultValue\": \"5\",\n \"description\": \"When sync fails, interval in seconds between each retry.\",\n \"id\": \"clock.ntp.retry.interval\",\n \"isRequired\": true,\n \"min\": \"1\",\n \"name\": \"clock.ntp.retry.interval\",\n \"type\": \"INTEGER\"\n },\n {\n \"defaultValue\": \"3600\",\n \"description\": \"Whether or not to sync the clock and if so, the frequency in seconds. If less than zero - no update, if equal to zero - sync once at startup, if greater than zero - the frequency in seconds to perform a new clock sync\",\n \"id\": \"clock.ntp.refresh-interval\",\n \"isRequired\": true,\n \"name\": \"clock.ntp.refresh-interval\",\n \"type\": \"INTEGER\"\n },\n {\n \"defaultValue\": \"/dev/rtc0\",\n \"description\": \"The RTC File Name. It defaults to /dev/rtc0. This option is not used if chrony-advanced option is selected in clock.provider.\",\n \"id\": \"rtc.filename\",\n \"isRequired\": true,\n \"name\": \"RTC File Name\",\n \"type\": \"STRING\"\n },\n {\n \"description\": \"Chrony configuration file.|TextArea\",\n \"id\": \"chrony.advanced.config\",\n \"isRequired\": false,\n \"name\": \"Chrony Configuration\",\n \"type\": \"STRING\"\n }\n ],\n \"description\": \"ClockService Configuration\",\n \"icon\": [\n {\n \"resource\": \"ClockService\",\n \"size\": 32\n }\n ],\n \"id\": \"org.eclipse.kura.clock.ClockService\",\n \"name\": \"ClockService\"\n },\n \"pid\": \"org.eclipse.kura.clock.ClockService\",\n \"properties\": {\n \"clock.ntp.host\": {\n \"type\": \"STRING\",\n \"value\": \"0.pool.ntp.org\"\n },\n \"clock.ntp.max-retry\": {\n \"type\": \"INTEGER\",\n \"value\": 0\n },\n \"clock.ntp.port\": {\n \"type\": \"INTEGER\",\n \"value\": 123\n },\n \"clock.ntp.refresh-interval\": {\n \"type\": \"INTEGER\",\n \"value\": 3600\n },\n \"clock.ntp.retry.interval\": {\n \"type\": \"INTEGER\",\n \"value\": 5\n },\n \"clock.ntp.timeout\": {\n \"type\": \"INTEGER\",\n \"value\": 10000\n },\n \"clock.provider\": {\n \"type\": \"STRING\",\n \"value\": \"java-ntp\"\n },\n \"clock.set.hwclock\": {\n \"type\": \"BOOLEAN\",\n \"value\": true\n },\n \"enabled\": {\n \"type\": \"BOOLEAN\",\n \"value\": true\n },\n \"kura.service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.clock.ClockService\"\n },\n \"rtc.filename\": {\n \"type\": \"STRING\",\n \"value\": \"/dev/rtc0\"\n },\n \"service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.clock.ClockService\"\n }\n }\n },\n {\n \"definition\": {\n \"ad\": [\n {\n \"defaultValue\": \"(kura.service.pid=org.eclipse.kura.ssl.SslManagerService)\",\n \"description\": \"Specifies, as an OSGi target filter, the pid of the SslManagerService used to create SSL connections for downloading packages.\",\n \"id\": \"SslManagerService.target\",\n \"isRequired\": true,\n \"name\": \"SslManagerService Target Filter\",\n \"type\": \"STRING\"\n }\n ],\n \"description\": \"This service is responsible of managing the deployment packages installed on the system.\",\n \"id\": \"org.eclipse.kura.deployment.agent\",\n \"name\": \"DeploymentAgent\"\n },\n \"pid\": \"org.eclipse.kura.deployment.agent\",\n \"properties\": {\n \"SslManagerService.target\": {\n \"type\": \"STRING\",\n \"value\": \"(kura.service.pid=org.eclipse.kura.ssl.SslManagerService)\"\n },\n \"kura.service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.deployment.agent\"\n },\n \"service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.deployment.agent\"\n }\n }\n }\n ]\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#createfactorycomponentconfigurationsrequest","title":"CreateFactoryComponentConfigurationsRequest","text":"An object describing a factory component instance creation request. Properties:
configs: array
The set of configurations to be created
array elements: object
An object describing a factory component confguration. Properties:
pid: string
The component pid.
string
The component factory pidobject
bool
true
value will be used as default if not explicitly specified Defines whether a new snapshot should be created after that the factory component configuration instances have been created.{\n \"configs\": [\n {\n \"factoryPid\": \"org.eclipse.kura.core.db.H2DbServer\",\n \"pid\": \"testComponent\",\n \"properties\": {\n \"db.server.type\": {\n \"type\": \"STRING\",\n \"value\": \"WEB\"\n }\n }\n },\n {\n \"factoryPid\": \"org.eclipse.kura.core.db.H2DbServer\",\n \"pid\": \"thirdComponent\"\n }\n ],\n \"takeSnapshot\": true\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#updatecomponentconfigurationrequest","title":"UpdateComponentConfigurationRequest","text":"An object that describes a set of configurations that need to be updated. Properties:
array
The configurations to be updated. The ocd
field can be omitted, it will be ignored if specified.object
bool
true
value will be used as default if not explicitly specified Defines whether a new snapshot should be created after that the component configurations have been applied.{\n \"configs\": [\n {\n \"pid\": \"org.eclipse.kura.cloud.app.command.CommandCloudApp\",\n \"properties\": {\n \"command.enable\": {\n \"type\": \"BOOLEAN\",\n \"value\": true\n },\n \"command.timeout\": {\n \"type\": \"INTEGER\",\n \"value\": 60\n }\n }\n },\n {\n \"pid\": \"org.eclipse.kura.position.PositionService\",\n \"properties\": {\n \"parity\": {\n \"type\": \"STRING\",\n \"value\": 0\n }\n }\n }\n ],\n \"takeSnapshot\": true\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#deletefactorycomponentconfigurationsrequest","title":"DeleteFactoryComponentConfigurationsRequest","text":"An object describing a factory component instance delete request. Properties:
array
The list of the pids of the factory component instances to be deleted.string
The component pid.bool
true
value will be used as default if not explicitly specified Defines whether a new snapshot should be created after that the factory component configuration instances have been deleted.{\n \"pids\": [\n \"testComponent\",\n \"otherComponent\"\n ],\n \"takeSnapshot\": true\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#pidset","title":"PidSet","text":"Represents a set of pids or factory pids. Properties:
array
The set of pidsstring
The pid{\n \"pids\": [\n \"org.eclipse.kura.deployment.agent\",\n \"org.eclipse.kura.clock.ClockService\"\n ]\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#snaphsotid","title":"SnaphsotId","text":"An object describing the identifier of a configuration snapshot. Properties:
number
The snapshot id{\n \"id\": 163655959932\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#genericfailurereport","title":"GenericFailureReport","text":"An object reporting a failure message. Properties:
string
A message describing the failure.{\n \"message\": \"An unexpected error occurred.\"\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#batchfailurereport","title":"BatchFailureReport","text":"An object that is returned by requests that involve multiple operations, when at least one operation failed. This object report an error message for each of the operations that failed. The operations are identified by an id, see request documentation for more details. If an operation is not listed by this object, then the operation succeeded. Properties:
failures: array
The list of operations that failed.
array elements: object
An object reporting details about an operation failure. Properties:
id: string
An identifier of the failed operation.
string
A message describing the failure.{\n \"failures\": [\n {\n \"id\": \"create:testComponent\",\n \"message\": \"Invalid parameter. pid testComponent already exists\"\n },\n {\n \"id\": \"create:otherComponent\",\n \"message\": \"Invalid parameter. pid otherComponent already exists\"\n }\n ]\n}\n
"},{"location":"references/rest-apis/rest-deploy-api/","title":"Rest Deploy v2 API","text":"The DeploymentRestService
APIs provides methods to manage the installed deployment packages. Identities with rest.deploy
permissions can access these APIs.
/deploy/v2/
[{ \"name\": \"packageName\", \"version\": \"packageVersion\"}]\n
"},{"location":"references/rest-apis/rest-deploy-api/#install-package-from-url","title":"Install package from URL","text":"/deploy/v2/_install
{\n \"url\": \"deploymentPackageUrl\"\n}\n
Example:
{\n \"url\": \"http://download.eclipse.org/kura/releases/4.1.0/org.eclipse.kura.demo.heater_1.0.500.dp\"\n}\n
Please note that the url can refer to a .dp
already in the device filesystem.
\"REQUEST_RECEIVED\"\n
"},{"location":"references/rest-apis/rest-deploy-api/#install-package-from-upload","title":"Install package from upload","text":"/deploy/v2/_upload
The POST request body should be encoded in the multipart/form-data
enctype
, thus allowing for the upload of the Deployment Package file. The uploaded file is expected to be added in the file
field of the form.
Content-Type
: multipart/form-data
file
Example using curl
:
curl -X POST -k -u $USERNAME:$PASSWORD \\\n --header 'Content-Type: multipart/form-data' \\\n --form 'file=@\"/path/to/your/file.dp\"' \\\n https://$ADDRESS/services/deploy/v2/_upload\n
"},{"location":"references/rest-apis/rest-deploy-api/#responses_2","title":"Responses","text":"\"REQUEST_RECEIVED\"\n
"},{"location":"references/rest-apis/rest-deploy-api/#uninstall-a-package","title":"Uninstall a package","text":"/deploy/v2/{name}
\"REQUEST_RECEIVED\"\n
"},{"location":"references/rest-apis/rest-deploy-api/#get-eclipse-marketplace-package-descriptor","title":"Get Eclipse Marketplace Package Descriptor","text":"/deploy/v2/_packageDescriptor
{\n \"url\": \"deploymentPackageUrl\"\n}\n
Example:
{\n \"url\": \"http://marketplace.eclipse.org/marketplace-client-intro?mpc_install=5514714\"\n}\n
"},{"location":"references/rest-apis/rest-deploy-api/#responses_4","title":"Responses","text":"{\n \"nodeId\":\"5514714\",\n \"url\":\"https://marketplace.eclipse.org/content/ai-wire-component-eclipse-kura-5\",\n \"dpUrl\":\"https://download.eclipse.org/kura/releases/5.3.0/org.eclipse.kura.wire.ai.component.provider-1.2.0.dp\",\n \"minKuraVersion\":\"5.1.0\",\n \"maxKuraVersion\":\"\",\n \"currentKuraVersion\":\"5.4.0\",\n \"isCompatible\":true\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v1/","title":"Rest Identity V1 API","text":"Warning
This API id deprecated and superseded by the Identity V2 REST APIs.
Note
This API can also be accessed via the RequestHandler with app-id: IDN-V1
.
The IdentityRestService
APIs provides methods to manage the system identities. Unless otherwise specified, identities with rest.identity
permissions can access these APIs.
services/identity/v1/identities
{\n \"userName\": \"username\",\n \"password\": \"password\",\n \"passwordChangeNeeded\": false,\n \"passwordAuthEnabled\": true,\n \"permissions\": [\n \"rest.identity\"\n ]\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v1/#responses","title":"Responses","text":"services/identity/v1/identities/byName
{\n \"userName\": \"username\"\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v1/#responses_1","title":"Responses","text":"{\n \"userName\": \"kura.user.username\",\n \"passwordAuthEnabled\": false,\n \"passwordChangeNeeded\": false,\n \"permissions\": []\n}\n
userName
does not existservices/identity/v1/definedPermissions
No specific permission is required to access this resource.
"},{"location":"references/rest-apis/rest-identity-api-v1/#responses_2","title":"Responses","text":"{\n \"permissions\": [\n \"rest.command\",\n \"rest.inventory\",\n \"rest.configuration\",\n \"rest.tamper.detection\",\n \"rest.security\",\n \"kura.cloud.connection.admin\",\n \"rest.position\",\n \"kura.packages.admin\",\n \"kura.device\",\n \"rest.wires.admin\",\n \"kura.admin\",\n \"rest.keystores\",\n \"rest.assets\",\n \"rest.system\",\n \"kura.maintenance\",\n \"kura.wires.admin\",\n \"rest.identity\"\n ]\n}\n
services/identity/v1/identities
{\n \"userConfig\": [\n {\n \"userName\": \"admin\",\n \"passwordAuthEnabled\": true,\n \"passwordChangeNeeded\": false,\n \"permissions\": [\n \"kura.admin\"\n ]\n },\n {\n \"userName\": \"appadmin\",\n \"passwordAuthEnabled\": true,\n \"passwordChangeNeeded\": true,\n \"permissions\": [\n \"kura.cloud.connection.admin\",\n \"kura.packages.admin\",\n \"kura.wires.admin\"\n ]\n }\n ]\n}\n
services/identity/v1/passwordRequirements
No specific permission is required to access this resource.
"},{"location":"references/rest-apis/rest-identity-api-v1/#responses_4","title":"Responses","text":"{\n \"passwordMinimumLength\": 8,\n \"passwordRequireDigits\": false,\n \"passwordRequireSpecialChars\": false,\n \"passwordRequireBothCases\": false\n}\n
services/identity/v1/identities
{\n \"userName\": \"username\",\n \"password\": \"password\",\n \"passwordChangeNeeded\": false,\n \"passwordAuthEnabled\": true,\n \"permissions\": [\n \"rest.identity\"\n ]\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v1/#responses_5","title":"Responses","text":"services/identity/v1/identities
{\n \"userName\": \"username\"\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v1/#responses_6","title":"Responses","text":"userName
does not existNote
This API can also be accessed via the RequestHandler with app-id: IDN-V2
.
The IdentityRestService
APIs provides methods to manage the system identities. Unless otherwise specified, identities with rest.identity
permissions can access these APIs.
services/identity/v2/identities
{\n \"name\": \"username\"\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#responses","title":"Responses","text":"name
(eg: nme
)identity
field is used to get only the name of specific identity. It is also possible to retrieve information about the specific user's component configuration, specifying the type of interest.services/identity/v2/identities/byName
{\n \"identity\": {\n \"name\": \"test\"\n }\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#response","title":"Response","text":"{\n \"identity\": {\n \"name\": \"username\"\n }\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#request_2","title":"Request","text":"{\n \"identity\": {\n \"name\": \"username\"\n }, \n \"configurationComponents\": [\"AdditionalConfigurations\", \"AssignedPermissions\", \"PasswordConfiguration\"]\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#response_1","title":"Response","text":"{\n \"identity\": {\n \"name\": \"username\"\n },\n \"permissionConfiguration\": {\n \"permissions\": [\n {\n \"name\": \"rest.identity\"\n }\n ]\n },\n \"passwordConfiguration\": {\n \"passwordChangeNeeded\": false,\n \"passwordAuthEnabled\": true\n },\n \"additionalConfigurations\": {\n \"configurations\": []\n }\n}\n
name
(eg: nme
)identity
field is used to get only the name of specific identity. It is also possible to retrieve information about the specific user's component default configuration, specifying the type of interest. This method accepts also non-existing user's name as input: in this way it's possible to retrieve which is the default configuration applied when a user is created with the name
field only.services/identity/v2/identities/default/byName
{\n\"identity\": {\n \"name\": \"username\"\n }\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#response_2","title":"Response","text":"{\n \"identity\": {\n \"name\": \"username\"\n }\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#request_4","title":"Request","text":"{\n \"identity\": {\n \"name\": \"username\"\n }, \n \"configurationComponents\": [\"AdditionalConfigurations\", \"AssignedPermissions\", \"PasswordConfiguration\"]\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#response_3","title":"Response","text":"{\n \"identity\": {\n \"name\": \"username\"\n },\n \"permissionConfiguration\": {\n \"permissions\": []\n },\n \"passwordConfiguration\": {\n \"passwordChangeNeeded\": false,\n \"passwordAuthEnabled\": false\n },\n \"additionalConfigurations\": {\n \"configurations\": []\n }\n}\n
name
(eg: nme
)services/identity/v2/permissions
{\n \"name\": \"permission\"\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#responses_1","title":"Responses","text":"identity
body field, or also the configurationComponents
one.services/identity/v2/identities/validate
{\n \"identity\": {\n \"name\": \"username\"\n }, \n \"configurationComponents\": [\"AdditionalConfigurations\", \"AssignedPermissions\", \"PasswordConfiguration\"]\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#responses_2","title":"Responses","text":"name
(eg: nme
)services/identity/v2/definedPermissions
No specific permission is required to access this resource.
"},{"location":"references/rest-apis/rest-identity-api-v2/#responses_3","title":"Responses","text":"[\n {\n \"name\": \"rest.identity\"\n },\n {\n \"name\": \"rest.wires.admin\"\n },\n {\n \"name\": \"kura.wires.admin\"\n },\n {\n \"name\": \"kura.network.admin\"\n },\n {\n \"name\": \"rest.network.status\"\n },\n {\n \"name\": \"test-permission\"\n },\n {\n \"name\": \"rest.keystores\"\n },\n {\n \"name\": \"rest.assets\"\n },\n {\n \"name\": \"rest.network.configuration\"\n },\n {\n \"name\": \"kura.admin\"\n },\n {\n \"name\": \"rest.cloudconnection\"\n },\n {\n \"name\": \"kura.device\"\n },\n {\n \"name\": \"rest.system\"\n },\n {\n \"name\": \"kura.maintenance\"\n },\n {\n \"name\": \"kura.packages.admin\"\n },\n {\n \"name\": \"rest.tamper.detection\"\n },\n {\n \"name\": \"rest.deploy\"\n },\n {\n \"name\": \"rest.configuration\"\n },\n {\n \"name\": \"kura.cloud.connection.admin\"\n },\n {\n \"name\": \"rest.command\"\n },\n {\n \"name\": \"rest.inventory\"\n },\n {\n \"name\": \"rest.position\"\n },\n {\n \"name\": \"rest.security\"\n }\n]\n
services/identity/v2/identities
[\n {\n \"identity\": {\n \"name\": \"admin\"\n },\n \"permissionConfiguration\": {\n \"permissions\": [\n {\n \"name\": \"kura.admin\"\n }\n ]\n },\n \"passwordConfiguration\": {\n \"passwordChangeNeeded\": false,\n \"passwordAuthEnabled\": true\n },\n \"additionalConfigurations\": {\n \"configurations\": []\n }\n },\n {\n \"identity\": {\n \"name\": \"appadmin\"\n },\n \"permissionConfiguration\": {\n \"permissions\": [\n {\n \"name\": \"kura.packages.admin\"\n },\n {\n \"name\": \"kura.cloud.connection.admin\"\n },\n {\n \"name\": \"kura.wires.admin\"\n }\n ]\n },\n \"passwordConfiguration\": {\n \"passwordChangeNeeded\": true,\n \"passwordAuthEnabled\": true\n },\n \"additionalConfigurations\": {\n \"configurations\": []\n }\n },\n {\n \"identity\": {\n \"name\": \"netadmin\"\n },\n \"permissionConfiguration\": {\n \"permissions\": [\n {\n \"name\": \"kura.device\"\n },\n {\n \"name\": \"kura.network.admin\"\n },\n {\n \"name\": \"kura.cloud.connection.admin\"\n }\n ]\n },\n \"passwordConfiguration\": {\n \"passwordChangeNeeded\": true,\n \"passwordAuthEnabled\": true\n },\n \"additionalConfigurations\": {\n \"configurations\": []\n }\n }\n]\n
services/identity/v2/passwordStrenghtRequirements
No specific permission is required to access this resource.
"},{"location":"references/rest-apis/rest-identity-api-v2/#responses_5","title":"Responses","text":"{\n \"passwordMinimumLength\": 8,\n \"digitsRequired\": false,\n \"specialCharactersRequired\": false,\n \"bothCasesRequired\": false\n}\n
services/identity/v2/identities
{\n \"identity\": {\n \"name\": \"username\"\n },\n \"permissionConfiguration\": {\n \"permissions\": [\n {\n \"name\": \"rest.identity\"\n }\n ]\n },\n \"passwordConfiguration\": {\n \"passwordChangeNeeded\": false,\n \"passwordAuthEnabled\": true,\n \"password\": \"password123\"\n }\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#responses_6","title":"Responses","text":"name
(eg: nme
)name
.services/identity/v2/identities
{\n \"name\": \"username\"\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#responses_7","title":"Responses","text":"username
does not existname
(eg: nme
)name
.services/identity/v2/permissions
{\n \"name\": \"permission\"\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#responses_8","title":"Responses","text":"permission
does not existname
(eg: nme
)/services/inventory/v1/inventory
{\n \"inventory\":[\n {\n \"name\":\"adduser\",\n \"version\":\"3.118\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"com.eclipsesource.jaxrs.provider.gson\",\n \"version\":\"2.3.0.201602281253\",\n \"type\":\"BUNDLE\"\n },\n {\n \"name\":\"org.eclipse.kura.example.beacon\",\n \"version\":\"1.0.500\",\n \"type\":\"DP\"\n }\n ]\n}\n
/services/inventory/v1/bundles
{\n \"bundles\":[\n {\n \"name\":\"org.eclipse.osgi\",\n \"version\":\"3.16.0.v20200828-0759\",\n \"id\":0,\n \"state\":\"ACTIVE\",\n \"signed\":true\n },\n {\n \"name\":\"org.eclipse.equinox.cm\",\n \"version\":\"1.4.400.v20200422-1833\",\n \"id\":1,\n \"state\":\"ACTIVE\",\n \"signed\":false\n }\n ]\n}\n
/services/inventory/v1/bundles/_start
{ \n\"name\":\"org.eclipse.osgi\",\n}\n
"},{"location":"references/rest-apis/rest-inventory-api/#responses","title":"Responses","text":"/services/inventory/v1/bundles/_stop
{ \n\"name\":\"org.eclipse.osgi\",\n}\n
"},{"location":"references/rest-apis/rest-inventory-api/#responses_1","title":"Responses","text":"/services/inventory/v1/deploymentPackages
{\n \"deploymentPackages\":[\n {\n \"name\":\"org.eclipse.kura.example.beacon\",\n \"version\":\"1.0.500\",\n \"signed\":false,\n \"bundles\":[\n {\n \"name\":\"org.eclipse.kura.example.beacon\",\n \"version\":\"1.0.500\",\n \"id\": 171,\n \"state\": \"ACTIVE\",\n \"signed\": false\n }\n ]\n }\n ]\n}\n
/services/inventory/v1/systemPackages
{\n \"systemPackages\":[\n {\n \"name\":\"adduser\",\n \"version\":\"3.118\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"alsa-utils\",\n \"version\":\"1.1.8-2\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"ansible\",\n \"version\":\"2.7.7+dfsg-1\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"apparmor\",\n \"version\":\"2.13.2-10\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"apt\",\n \"version\":\"1.8.2.1\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"apt-listchanges\",\n \"version\":\"3.19\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"apt-transport-https\",\n \"version\":\"1.8.2.2\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"apt-utils\",\n \"version\":\"1.8.2.1\",\n \"type\":\"DEB\"\n }\n ]\n}\n
/services/inventory/v1/containers
{\n \"containers\":\n [\n {\n \"name\":\"container_1\",\n \"version\":\"nginx:latest\",\n \"type\":\"DOCKER\",\n \"state\":\"active\"\n }\n ]\n}\n
/services/inventory/v1/containers/_start
{\n \"name\":\"container_1\",\n \"version\": \"nginx:latest\",\n}\n
"},{"location":"references/rest-apis/rest-inventory-api/#responses_2","title":"Responses","text":"/services/inventory/v1/containers/_stop
{\n \"name\":\"container_1\",\n \"version\": \"nginx:latest\",\n}\n
"},{"location":"references/rest-apis/rest-inventory-api/#responses_3","title":"Responses","text":"/services/inventory/v1/images
{\n \"containers\":\n [\n {\n \"name\":\"nginx\",\n \"version\":\"latest\",\n \"type\":\"ContainerImage\",\n }\n ]\n}\n
/services/inventory/v1/images/_delete
{\n \"name\":\"nginx\",\n \"version\":\"latest\",\n}\n
"},{"location":"references/rest-apis/rest-inventory-api/#responses_4","title":"Responses","text":"- `ACTIVE`: Container is running\n- `INSTALLED`: Container is starting\n- `UNINSTALLED`: Container has failed, or is stopped\n- `UNKNOWN`: Container state can not be determined\n
"},{"location":"references/rest-apis/rest-inventory-api/#container-states","title":"Container States","text":"- `active`: Container is running\n- `installed`: Container is starting\n- `uninstalled`: Container has failed, or is stopped\n- `unknown`: Container state can not be determined\n
"},{"location":"references/rest-apis/rest-network-configuration-api/","title":"Network Configuration V1 REST APIs","text":"This section describes the networkConfiguration/v1
REST APIs, that allow to retrieve information about the network configuration of the running system. The services pid
for which it's possible to obtain and update the configurations are:
org.eclipse.kura.net.admin.NetworkConfigurationService
: which manages the network configuration of the system, so the network interfaces along with their network configuration (Ip4/Ip6 settings, DHCP, Nat, and so on)org.eclipse.kura.net.admin.FirewallConfigurationService
: which manages the Ip4 firewall configurations (open ports, port forwarding and masquerading for IPv4 protocol)org.eclipse.kura.net.admin.ipv6.FirewallConfigurationServiceIPv6
: which manages the Ip6 firewall configurations (open ports, port forwarding and masquerading for IPv6 protocol)To access these REST APIs, an identity with rest.network.configuration
permission assigned is required.
/services/networkConfiguration/v1/configurableComponents
/services/networkConfiguration/v1/configurableComponents/configurations
pid
, ocd
and properties
./services/networkConfiguration/v1/configurableComponents/configurations/byPid
pid
, ocd
and properties
./services/networkConfiguration/v1/configurableComponents/configurations/byPid/_default
pid
, ocd
and properties
./services/networkConfiguration/v1/configurableComponents/configurations/_update
update:$pid
for component update operations, where $pid
is the pid of the instance, and snapshot
, for the snapshot creation operation. In case of an unexpected failure, a generic error response will be returned.Warning
factoryComponents
endopoints are available in the current version of Kura for future compatibility. Currently, as of Kura 5.4.0, there are no network related components that are factory components.
The endopoints that should return a list of pids will always return an empty array, while those that should create, delete or update a component will always return a 500 error.
"},{"location":"references/rest-apis/rest-network-configuration-api/#getfactorycomponents","title":"GET/factoryComponents","text":"/services/networkConfiguration/v1/factoryComponents
/services/networkConfiguration/v1/factoryComponents
500
description : In case of processing errors, the device will attempt to return a detailed error response containing a message describing the failure reason for each operation. The operation ids are the following: create:$pid
for component creation operations, where $pid
is the pid of the instance, and snapshot
, for the snapshot creation operation. In case of an unexpected failure, a generic error response will be returned.
response body :
/services/networkConfiguration/v1/factoryComponents/byPid
delete:$pid
for component delete operations, where $pid
is the pid of the instance, and snapshot
, for the snapshot creation operation. In case of an unexpected failure, a generic error response will be returned./services/networkConfiguration/v1/factoryComponents/ocd
pid
property of the received configurations will report the factory pid, the ocd
field will contain the definition, the properties
field will not be present./services/networkConfiguration/v1/factoryComponents/ocd/byFactoryPid
pid
property of the received configurations will report the factory pid, the ocd
field will contain the definition, the properties
field will not be present. If the OCD for a given factory pid cannot be found, it will not be included in the result.An object that is returned by requests that involve multiple operations, when at least one operation failed. This object report an error message for each of the operations that failed. The operations are identified by an id, see request documentation for more details. If an operation is not listed by this object, then the operation succeeded. Properties:
failures: array
The list of operations that failed.
array elements: object
An object reporting details about an operation failure. Properties:
id: string
An identifier of the failed operation.
string
A message describing the failure.{\n \"failures\": [\n {\n \"id\": \"create:testComponent\",\n \"message\": \"Invalid parameter. pid testComponent already exists\"\n },\n {\n \"id\": \"create:otherComponent\",\n \"message\": \"Invalid parameter. pid otherComponent already exists\"\n }\n ]\n}\n
"},{"location":"references/rest-apis/rest-network-configuration-api/#componentconfigurationlist","title":"ComponentConfigurationList","text":"Represents a list of component configurations. Properties:
array
The component configurationsobject
{\n \"configs\": [\n {\n \"pid\": \"org.eclipse.kura.net.admin.FirewallConfigurationService\",\n \"definition\": {\n \"ad\": [\n {\n \"name\": \"firewall.open.ports\",\n \"description\": \"The list of firewall opened ports.\",\n \"id\": \"firewall.open.ports\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"\",\n \"isRequired\": true\n },\n {\n \"name\": \"firewall.port.forwarding\",\n \"description\": \"The list of firewall port forwarding rules.\",\n \"id\": \"firewall.port.forwarding\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"\",\n \"isRequired\": true\n },\n {\n \"name\": \"firewall.nat\",\n \"description\": \"The list of firewall NAT rules.\",\n \"id\": \"firewall.nat\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"\",\n \"isRequired\": true\n }\n ],\n \"name\": \"FirewallConfigurationService\",\n \"description\": \"Firewall Configuration Service\",\n \"id\": \"org.eclipse.kura.net.admin.FirewallConfigurationService\"\n },\n \"properties\": {\n \"firewall.open.ports\": {\n \"value\": \"22,tcp,0.0.0.0/0,eth0,,,,#;22,tcp,0.0.0.0/0,wlan0,,,,#;443,tcp,0.0.0.0/0,eth0,,,,#;443,tcp,0.0.0.0/0,wlan0,,,,#;4443,tcp,0.0.0.0/0,eth0,,,,#;4443,tcp,0.0.0.0/0,wlan0,,,,#;1450,tcp,0.0.0.0/0,eth0,,,,#;1450,tcp,0.0.0.0/0,wlan0,,,,#;5002,tcp,127.0.0.1/32,,,,,#;53,udp,0.0.0.0/0,eth0,,,,#;53,udp,0.0.0.0/0,wlan0,,,,#;67,udp,0.0.0.0/0,eth0,,,,#;67,udp,0.0.0.0/0,wlan0,,,,#;8000,tcp,0.0.0.0/0,eth0,,,,#;8000,tcp,0.0.0.0/0,wlan0,,,,#\",\n \"type\": \"STRING\"\n },\n \"firewall.port.forwarding\": {\n \"value\": \"\",\n \"type\": \"STRING\"\n },\n \"firewall.nat\": {\n \"value\": \"\",\n \"type\": \"STRING\"\n },\n \"kura.service.pid\": {\n \"value\": \"org.eclipse.kura.net.admin.FirewallConfigurationService\",\n \"type\": \"STRING\"\n },\n \"service.pid\": {\n \"value\": \"org.eclipse.kura.net.admin.FirewallConfigurationService\",\n \"type\": \"STRING\"\n }\n }\n },\n {\n \"pid\": \"org.eclipse.kura.net.admin.ipv6.FirewallConfigurationServiceIPv6\",\n \"definition\": {\n \"ad\": [\n {\n \"name\": \"firewall.ipv6.open.ports\",\n \"description\": \"The list of firewall opened ports.\",\n \"id\": \"firewall.ipv6.open.ports\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"\",\n \"isRequired\": true\n },\n {\n \"name\": \"firewall.ipv6.port.forwarding\",\n \"description\": \"The list of firewall port forwarding rules.\",\n \"id\": \"firewall.ipv6.port.forwarding\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"\",\n \"isRequired\": true\n },\n {\n \"name\": \"firewall.ipv6.nat\",\n \"description\": \"The list of firewall NAT rules.\",\n \"id\": \"firewall.ipv6.nat\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"\",\n \"isRequired\": true\n }\n ],\n \"name\": \"FirewallConfigurationServiceIPv6\",\n \"description\": \"Firewall Configuration Service IPV6\",\n \"id\": \"org.eclipse.kura.net.admin.ipv6.FirewallConfigurationServiceIPv6\"\n },\n \"properties\": {\n \"firewall.ipv6.port.forwarding\": {\n \"value\": \"\",\n \"type\": \"STRING\"\n },\n \"firewall.ipv6.nat\": {\n \"value\": \"\",\n \"type\": \"STRING\"\n },\n \"firewall.ipv6.open.ports\": {\n \"value\": \"1234,tcp,0:0:0:0:0:0:0:0/0,,,,,#\",\n \"type\": \"STRING\"\n },\n \"kura.service.pid\": {\n \"value\": \"org.eclipse.kura.net.admin.ipv6.FirewallConfigurationServiceIPv6\",\n \"type\": \"STRING\"\n },\n \"service.pid\": {\n \"value\": \"org.eclipse.kura.net.admin.ipv6.FirewallConfigurationServiceIPv6\",\n \"type\": \"STRING\"\n }\n }\n }\n ]\n}\n
"},{"location":"references/rest-apis/rest-network-configuration-api/#genericfailurereport","title":"GenericFailureReport","text":"An object reporting a failure message. Properties:
string
A message describing the failure.{\n \"message\": \"An unexpected error occurred.\"\n}\n
"},{"location":"references/rest-apis/rest-network-configuration-api/#pidset","title":"PidSet","text":"Represents a set of pids or factory pids. Properties:
array
The set of pidsstring
The pid{\n \"pids\": [\n \"org.eclipse.kura.net.admin.ipv6.FirewallConfigurationServiceIPv6\",\n \"org.eclipse.kura.net.admin.NetworkConfigurationService\",\n \"org.eclipse.kura.net.admin.FirewallConfigurationService\"\n ]\n}\n
"},{"location":"references/rest-apis/rest-network-configuration-api/#updatecomponentconfigurationrequest","title":"UpdateComponentConfigurationRequest","text":"An object that describes a set of configurations that need to be updated. Properties:
array
The configurations to be updated. The ocd
field can be omitted, it will be ignored if specified.object
bool
true
value will be used as default if not explicitly specified Defines whether a new snapshot should be created after that the component configurations have been applied.{\n \"configs\": [\n {\n \"pid\": \"org.eclipse.kura.net.admin.ipv6.FirewallConfigurationServiceIPv6\",\n \"properties\": {\n \"firewall.ipv6.open.ports\": {\n \"value\": \"1234,tcp,0:0:0:0:0:0:0:0/0,,,,,#\",\n \"type\": \"STRING\"\n }\n }\n },\n {\n \"pid\": \"org.eclipse.kura.net.admin.NetworkConfigurationService\",\n \"properties\": {\n \"net.interface.eth0.config.ip6.status\": {\n \"value\": \"netIPv6StatusUnmanaged\",\n \"type\": \"STRING\"\n }\n }\n }\n ],\n \"takeSnapshot\": true\n}\n
"},{"location":"references/rest-apis/rest-position-api/","title":"Position","text":"Note
This API can also be accessed via the RequestHandler with app-id: POS-V1
.
/services/position/v1/position
{\n //longitude of this position in degrees.\n \"longitude\": 7.729571119959449,\n\n //latitude of this position in degrees.\n \"latitude\": 50.45345802194789,\n\n //altitude of this position in meters.\n \"altitude\": 1000.0,\n\n //the ground speed of this position in meters per second.\n \"speed\": 1000.0,\n\n //the track of this position in degrees as a compass heading.\n \"track\": 1000.0\n\n //the gnss system used to retrieve position information\n \"gnssType\": [\n \"Gps\"\n ]\n}\n
{\n \"message\": \"Service unavailable. Position is not locked.\"\n}\n
/services/position/v1/dateTime
{\n //The dateTime string is formatted according to the ISO 8601 standard, and will always be in the UTC timezone. \n \"dateTime\": \"2023-07-19T18:26:38Z\"\n}\n
{\n \"message\": \"Service unavailable. Position is not locked.\"\n}\n
/services/position/v1/isLocked
{\n \"islocked\": false\n}\n
- 500 Internal Server Error"},{"location":"references/rest-apis/rest-security-api-v1/","title":"Rest Security V1 API","text":"Warning
This API id deprecated and superseded by the Security V2 REST APIs.
Note
This API can also be accessed via the RequestHandler with app-id: SEC-V1
.
This REST API requires a SecurityService implementation to be registered on the framework, which is not provided by the standard Kura distribution.
The SecurityRestService
APIs provides methods to manage the system security. Identities with rest.security
permissions can access these APIs.
services/security/v1/security-policy-fingerprint/reload
SecurityService
implementation is available)services/security/v1/command-line-fingerprint/reload
SecurityService
implementation is available)Note
Access to this resource doesn't require the rest.security
permission.
services/security/v1/debug-enabled
{\n \"enabled\":true\n}\n
SecurityService
implementation is available)Note
This API can also be accessed via the RequestHandler with app-id: SEC-V2
.
This REST API requires a SecurityService implementation to be registered on the framework, which is not provided by the standard Kura distribution.
The SecurityRestService
APIs provides methods to manage the system security. Identities with rest.security
permissions can access these APIs.
services/security/v2/security-policy-fingerprint/reload
SecurityService
implementation is available)services/security/v2/command-line-fingerprint/reload
SecurityService
implementation is available)services/security/v2/security-policy/apply-default-production
SecurityService
implementation is available)services/security/v2/security-policy/apply
<plain text security policy>\n
"},{"location":"references/rest-apis/rest-security-api-v2/#responses_3","title":"Responses","text":"SecurityService
implementation is available)Note
Access to this resource doesn't require the rest.security
permission.
services/security/v2/debug-enabled
{\n \"enabled\":true\n}\n
SecurityService
implementation is available)Note
This API can also be accessed via the RequestHandler with app-id: SVCLIST-V1
.
The SVCLIST-V1 cloud request handler and the corresponding REST APIs allow to retrieve the identifiers (kura.service.pid) of the service running on the system that match user provided search criteria.
KeystoreService
and TruststoreKeystoreService
defined by the org.eclipse.kura.ssl.SslManagerService
component.A list of serviceinterface names.
Properties:
interfaceNames: array
The list of service interface names.
string
A service interface name.{\n \"interfaceNames\": [\n \"org.eclipse.kura.security.keystore.KeystoreService\",\n \"org.eclipse.kura.configuration.ConfigurableComponent\"\n ]\n}\n
"},{"location":"references/rest-apis/rest-service-listing-api/#reference","title":"Reference","text":"A object specifying a service pid and a reference name.
Properties:
pid: string
The pid of the service containing the reference
referenceName: string
The reference name
{\n \"pid\": \"org.eclipse.kura.ssl.SslManagerService\",\n \"referenceName\": \"KeystoreService\"\n}\n
"},{"location":"references/rest-apis/rest-service-listing-api/#propertyfilter","title":"PropertyFilter","text":"A filter matching property keys and values. If the value
property omitted, the filter will match if the property is set, regardless of the value. If the service property value is of array or list type, the filter will match if at least one of the elements match.
Properties:
name: string
The property name that should be matched, it must not contain spaces
value: string
(optional) The property value that should be matched.
{\n \"name\": \"foo\",\n \"value\": \"bar\"\n}\n
{\n \"name\": \"foo\"\n}\n
"},{"location":"references/rest-apis/rest-service-listing-api/#notfilter","title":"NotFilter","text":"A filter that negates the result returned by the filter specified as the \"not\" propertiy.
Properties:
object
{\n \"not\": {\n \"name\": \"foo\",\n \"value\": \"bar\"\n }\n}\n
"},{"location":"references/rest-apis/rest-service-listing-api/#andfilter","title":"AndFilter","text":"A filter that matches if all filters specified by the \"and\" propertiy match.
Properties:
and: array
A list of filters that should be combined with the and operator
object
{\n \"and\": [\n {\n \"name\": \"foo\",\n \"value\": \"bar\"\n },\n {\n \"name\": \"baz\"\n }\n ]\n}\n
"},{"location":"references/rest-apis/rest-service-listing-api/#orfilter","title":"OrFilter","text":"A filter that matches if any of the filters specified by the \"or\" propertiy match.
Properties:
or: array
A list of filters that should be combined with the or operator
object
{\n \"or\": [\n {\n \"name\": \"foo\",\n \"value\": \"bar\"\n },\n {\n \"name\": \"baz\"\n }\n ]\n}\n
"},{"location":"references/rest-apis/rest-service-listing-api/#filter","title":"Filter","text":"A filter that operates on service properties. This object allows to specify basic property key/value matchers and the and
or
and not
operators.
Represents a set of pids or factory pids.
Properties:
pids: array
The set of pids
string
The pid{\n \"pids\": [\n \"org.eclipse.kura.cloud.app.command.CommandCloudApp\",\n \"org.eclipse.kura.cloud.CloudService\",\n \"org.eclipse.kura.cloud.publisher.CloudNotificationPublisher\",\n \"org.eclipse.kura.container.orchestration.provider.ContainerOrchestrationService\",\n \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\",\n \"org.eclipse.kura.core.deployment.CloudDeploymentHandlerV2\",\n \"org.eclipse.kura.crypto.CryptoService\",\n \"org.eclipse.kura.data.DataService\",\n \"org.eclipse.kura.db.H2DbService\",\n \"org.eclipse.kura.deployment.agent\"\n ]\n}\n
"},{"location":"references/rest-apis/rest-service-listing-api/#genericfailurereport","title":"GenericFailureReport","text":"An object reporting a failure message.
Properties:
string
A message describing the failure.The session management REST APIs allow to authenticate and establish an HTTP session. Using this APIs and creating a session is the recommended way for interact with Kura rest APIs from a browser based application.
The supported workflows are the following:
"},{"location":"references/rest-apis/rest-session-api/#login-and-resource-access-workflow","title":"Login and resource access workflow","text":"Try calling the GET/xsrfToken to get an XSRF token, if the request succeeds a vaild session is already available, it is possible to proceed to step 4.
Call the POST/login/password or POST/login/certificate providing the credentials to create a new session.
This request will return a session cookie with the response. The session cookie name is currently JSESSIONID
. It is important to provide the received cookies in successive requests using the Cookie HTTP request header. If this is not done, requests will fail with 401 code. If the request is performed by a browser, cookie management should be performed automatically.
If password authentication has been used and the response object reports that a password change is needed, perform the Update password workflow
Repeat step 1. to get an XSRF token.
Access the desired resources, set the XSRF token previously obtained as the value of the X-XSRF-Token
HTTP header on each request. If a reuqest fails with error code 401, proceed to step 2.
curl
","text":""},{"location":"references/rest-apis/rest-session-api/#1-login-with-usernamepassword-and-collect-the-session-cookie","title":"1. Login with username/password and collect the session cookie","text":"curl -k -X POST \\\n -H 'Content-Type: application/json' \\\n https://$ADDRESS/services/session/v1/login/password \\\n -d '{\"password\": \"$KURA_PASS\", \"username\": \"$KURA_USER\"}' -v\n
where:
$ADDRESS
: is the address of the Kura instance$KURA_USER
: is the Kura username$KURA_PASS
: is the Kura passwordin the log you should find a JSESSIONID
you'll use in subsequent requests
...\n< HTTP/1.1 200 OK\n< Date: Tue, 14 Nov 2023 08:17:26 GMT\n< Set-Cookie: JSESSIONID=myawesomecookie; Path=/; Secure; HttpOnly\n< Expires: Thu, 01 Jan 1970 00:00:00 GMT\n< Content-Type: application/json\n< Content-Length: 30\n<\n* Connection #0 to host 192.168.1.111 left intact\n{\"passwordChangeNeeded\":false}%\n
"},{"location":"references/rest-apis/rest-session-api/#2-retrieve-the-xsrf-token","title":"2. Retrieve the XSRF token","text":"curl -k -X GET \\\n -b \"JSESSIONID=myawesomecookie\" \\\n https://$ADDRESS/services/session/v1/xsrfToken\n
in the response you'll find your XSRF token you'll need to use in subsequent requests
{\"xsrfToken\":\"myawesometoken\"}%\n
"},{"location":"references/rest-apis/rest-session-api/#3-access-the-resource","title":"3. Access the resource","text":"Using the Cookie and the XSRF token you just retrieved you can access your desired resource
curl -k -X GET \\\n -H 'X-XSRF-Token: myawesometoken' \\\n -b \"JSESSIONID=myawesomecookie\" \\\n https://$ADDRESS/services/deploy/v2/\n
"},{"location":"references/rest-apis/rest-session-api/#update-password-workflow","title":"Update password workflow","text":"Get an XSRF token using the GET/xsrfToken endpoint.
Call the POST/changePassword, providing both the new and old password, make sure to include the X-XSRF-Token
HTTP header.
Repeat the Authentication and resource access workflow, starting from step 1.
Sessions will expire after an inactivity interval that can be configured using the Session Inactivity Interval (Seconds) RestService configuration parameter. After session expiration, a new login will be necessary.
In order to add protection against XSRF attacks, it is necessary to provide an token using the X-XSRF-Token
HTTP header in all requests. The token can be obtained using the GET/xsrfToken endpoint after a successful login.
Session will be invalidated if the current identity credentials are changed, in this case a new login will be necessary.
If a password change is required for the current identity, it will be necessary to perform the Update password workflow before being able to access the other resources.
"},{"location":"references/rest-apis/rest-session-api/#reference","title":"Reference","text":"identity/v1/passwordRequirements
endpoint.Represents the response for a successful authentication request.
Properties:
bool
Determines whether a password change is required for the current identity.{\n \"passwordChangeNeeded\": true\n}\n
"},{"location":"references/rest-apis/rest-session-api/#usernamepassword","title":"UsernamePassword","text":"Contains an username and password.
Properties:
username: string
The user name.
password: string
The user password.
{\n \"password\": \"bar\",\n \"username\": \"foo\"\n}\n
"},{"location":"references/rest-apis/rest-session-api/#xsrftoken","title":"XSRFToken","text":"An object containing an XSRF token.
Properties:
string
The XSRF token.{\n \"xsrfToken\": \"d2b68613-152f-41d5-8b5b-a19448ed0e4e\"\n}\n
"},{"location":"references/rest-apis/rest-session-api/#passwordchangerequest","title":"PasswordChangeRequest","text":"An object containing the current password and a new password.
Properties:
currentPassword: string
The current password.
newPassword: string
The new password.
{\n \"currentPassword\": \"foo\",\n \"newPassword\": \"bar\"\n}\n
"},{"location":"references/rest-apis/rest-session-api/#identityinfo","title":"IdentityInfo","text":"An object containing information about the current identity
Properties:
name: string
The name of the current identity.
passwordChangeNeeded: bool
Determines whether a password change is required for the current identity.
permissions: array
The list of permissions assigned to the current identity.
string
The permission name.{\n \"name\": \"foo\",\n \"passwordChangeNeeded\": false,\n \"permissions\": [\n \"rest.bar\",\n \"rest.assets\",\n \"rest.foo\"\n ]\n}\n
"},{"location":"references/rest-apis/rest-session-api/#authenticationinfo","title":"AuthenticationInfo","text":"An object containing information about the enabled authentication methods.
Properties:
passwordAuthenticationEnabled: bool
Reports whether authentication using the login/password
endpoint is enabled.
certificateAuthenticationEnabled: bool
Reports whether authentication using the login/certificate
endpoint is enabled.
certificateAuthenticationPorts: array
(optional) The list of ports available for certificate based authentication. This property will be present only if certificateAuthenticationEnabled
is true
string
A port that can be used for certificate based authentication.message: string
(optional) Reports the content of the Login Banner, if configured on the device. A browser based application should display this message to the user before login if this property is set. This property will be missing if the login banner is not enabled.
{\n \"certificateAuthenticationEnabled\": false,\n \"passwordAuthenticationEnabled\": true\n}\n
{\n \"certificateAuthenticationEnabled\": true,\n \"certificateAuthenticationPorts\": [\n 4443,\n 4444\n ],\n \"passwordAuthenticationEnabled\": true\n}\n
{\n \"certificateAuthenticationEnabled\": false,\n \"message\": \"login banner content\",\n \"passwordAuthenticationEnabled\": true\n}\n
"},{"location":"references/rest-apis/rest-session-api/#genericfailurereport","title":"GenericFailureReport","text":"An object reporting a failure message.
Properties:
string
A message describing the failure.Note
This API can also be accessed via the RequestHandler with app-id: SYS-V1
.
The SystemService
APIs return properties that are divided into 3 categories:
Identities with rest.system
permissions can access these APIs.
Note
Some of the listed properties, depending on the device, might not be available.
"},{"location":"references/rest-apis/rest-system-api/#get-methods","title":"GET methods","text":""},{"location":"references/rest-apis/rest-system-api/#get-framework-properties","title":"Get framework properties","text":"/services/system/v1/properties/framework
{\n \"biosVersion\": \"N/A\",\n \"cpuVersion\": \"unknown\",\n \"deviceName\": \"raspberry\",\n \"modelId\": \"raspberry\",\n \"modelName\": \"raspberry\",\n \"partNumber\": \"raspberry\",\n \"platform\": \"aarch64\",\n \"numberOfProcessors\": 4,\n \"totalMemory\": 506816,\n \"freeMemory\": 380379,\n \"serialNumber\": \"10000000ba7c7bfd\",\n \"javaHome\": \"/usr/lib/jvm/java-8-openjdk-armhf/jre\",\n \"javaVendor\": \"OpenJDK Runtime Environment\",\n \"javaVersion\": \"1.8.0_312-8u312-b07-1+rpi1-b07\",\n \"javaVmInfo\": \"mixed mode\",\n \"javaVmName\": \"OpenJDK Client VM\",\n \"javaVmVersion\": \"25.312-b07\",\n \"javaVmVendor\": \"Temurin\",\n \"jdkVendorVersion\": \"Zulu 8.70.0.24-SA-linux64\",\n \"osArch\": \"arm\",\n \"osDistro\": \"Linux\",\n \"osDistroVersion\": \"N/A\",\n \"osName\": \"Linux\",\n \"osVersion\": \"6.1.21-v8+ #1642 SMP PREEMPT Mon Apr 3 17:24:16 BST 2023\",\n \"isLegacyBluetoothBeaconScan\": false,\n \"isLegacyPPPLoggingEnabled\": true,\n \"primaryMacAddress\": \"E4:5F:01:35:7F:F4\",\n \"primaryNetworkInterfaceName\": \"eth0\",\n \"fileSeparator\": \"/\",\n \"firmwareVersion\": \"N/A\",\n \"kuraDataDirectory\": \"/opt/eclipse/kura/data\",\n \"kuraFrameworkConfigDirectory\": \"/opt/eclipse/kura/framework\",\n \"kuraHomeDirectory\": \"/opt/eclipse/kura\",\n \"kuraMarketplaceCompatibilityVersion\": \"5.4.0.SNAPSHOT\",\n \"kuraSnapshotsCount\": 10,\n \"kuraSnapshotsDirectory\": \"/opt/eclipse/kura/user/snapshots\",\n \"kuraStyleDirectory\": \"/opt/eclipse/kura/console/skin\",\n \"kuraTemporaryConfigDirectory\": \"/tmp/.kura\",\n \"kuraUserConfigDirectory\": \"/opt/eclipse/kura/user\",\n \"kuraVersion\": \"KURA_5.4.0-SNAPSHOT\",\n \"kuraHaveWebInterface\": true,\n \"kuraHaveNetAdmin\": true,\n \"kuraWifiTopChannel\": 2147483647,\n \"kuraDefaultNetVirtualDevicesConfig\": \"netIPv4StatusUnmanaged\",\n \"osgiFirmwareName\": \"Eclipse\",\n \"osgiFirmwareVersion\": \"1.10.0\",\n \"commandUser\": \"kura\",\n \"commandZipMaxUploadNumber\": 1024,\n \"commandZipMaxUploadSize\": 100\n}\n
/services/system/v1/properties/extended
{\n \"version\": \"1.0\",\n \"extendedProperties\": {\n \"Device Info 1\": {\n \"exampleKey1\": \"value1\",\n \"exampleKey2\": \"value2\"\n },\n \"Device Info 2\": {\n \"key1\": \"val1\",\n \"key2\": \"val2\"\n }\n }\n}\n
/services/system/v1/properties/kura
{\n \"kuraProperties\": {\n \"kura.platform\": \"aarch64\",\n \"org.osgi.framework.version\": \"1.10.0\",\n \"kura.user.config\": \"/opt/eclipse/kura/user\",\n \"java.vm.vendor\": \"Temurin\",\n \"kura.name\": \"Eclipse Kura\",\n \"file.command.zip.max.number\": \"1024\",\n \"kura.legacy.ppp.logging.enabled\": \"true\",\n \"kura.tmp\": \"/tmp/.kura\",\n \"kura.packages\": \"/opt/eclipse/kura/packages\",\n \"build.version\": \"buildNumber\",\n \"kura.log.download.journal.fields\": \"SYSLOG_IDENTIFIER,PRIORITY,MESSAGE,STACKTRACE\",\n \"kura.data\": \"/opt/eclipse/kura/data\",\n \"os.name\": \"Linux\",\n \"dpa.read.timeout\": \"60000\",\n \"file.upload.size.max\": \"-1\",\n \"console.device.management.service.ignore\": \"org.eclipse.kura.net.admin.NetworkConfigurationService,org.eclipse.kura.net.admin.FirewallConfigurationService\",\n \"kura.command.user\": \"kura\",\n \"kura.device.name\": \"raspberry\",\n \"kura.partNumber\": \"raspberry\",\n \"kura.project\": \"generic-arm32\",\n \"kura.company\": \"EUROTECH\",\n \"java.home\": \"/usr/lib/jvm/java-8-openjdk-armhf/jre\",\n \"version\": \"5.4.0-SNAPSHOT\",\n \"kura.style.dir\": \"/opt/eclipse/kura/console/skin\",\n \"kura.model.id\": \"raspberry\",\n \"file.separator\": \"/\",\n \"jdk.vendor.version\": \"Zulu 8.70.0.24-SA-linux64\",\n \"kura.model.name\": \"raspberry\",\n \"kura.serialNumber.provider\": \"cat /proc/cpuinfo | grep Serial | cut -d ' ' -f 2\",\n \"kura.have.web.inter\": \"true\",\n \"kura.legacy.bluetooth.beacon.scan\": \"false\",\n \"java.runtime.version\": \"1.8.0_312-8u312-b07-1+rpi1-b07\",\n \"kura.bios.version\": \"N/A\",\n \"kura.marketplace.compatibility.version\": \"KURA_5.4.0-SNAPSHOT\",\n \"kura.framework.config\": \"/opt/eclipse/kura/framework\",\n \"kura.firmware.version\": \"N/A\",\n \"kura.plugins\": \"/opt/eclipse/kura/plugins\",\n \"os.version\": \"6.1.21-v8+ #1642 SMP PREEMPT Mon Apr 3 17:24:16 BST 2023\",\n \"kura.version\": \"KURA_5.4.0-SNAPSHOT\",\n \"org.osgi.framework.vendor\": \"Eclipse\",\n \"java.runtime.name\": \"OpenJDK Runtime Environment\",\n \"kura.log.download.sources\": \"/var/log\",\n \"os.distribution\": \"Linux\",\n \"java.vm.name\": \"OpenJDK Client VM\",\n \"kura.primary.network.interface\": \"eth0\",\n \"kura.home\": \"/opt/eclipse/kura\",\n \"file.command.zip.max.size\": \"100\",\n \"os.arch\": \"arm\",\n \"os.distribution.version\": \"N/A\",\n \"file.upload.in.memory.size.threshold\": \"10240\",\n \"kura.net.virtual.devices.config\": \"unmanaged\",\n \"kura.snapshots\": \"/opt/eclipse/kura/user/snapshots\",\n \"kura.have.net.admin\": \"true\",\n \"java.vm.info\": \"mixed mode\",\n \"java.vm.version\": \"25.312-b07\",\n \"dpa.connection.timeout\": \"60000\",\n \"build.number\": \"generic-arm32-buildNumber\",\n \"ccs.status.notification.url\": \"ccs:log\"\n }\n}\n
This method allows to retrieve framework-related properties by their name. Available properties are in table Framework properties.
/services/system/v1/properties/framework/filter
{\n \"names\": [\"deviceName\", \"numberOfProcessors\", \"kuraHaveNetAdmin\"]\n}\n
"},{"location":"references/rest-apis/rest-system-api/#responses_3","title":"Responses","text":"{\n \"deviceName\": \"RASBPERRY PI 4\",\n \"numberOfProcessors\": 4,\n \"kuraHaveNetAdmin\": true\n}\n
This method allows to retrieve the extended properties and to filter them by group name.
/services/system/v1/properties/extended/filter
{\n \"groupNames\": [\"Device Info 1\"]\n}\n
"},{"location":"references/rest-apis/rest-system-api/#responses_4","title":"Responses","text":"{\n \"extendedProperties\": {\n \"Device Info 1\": {\n \"exampleKey1\": \"value1\",\n \"exampleKey2\": \"value2\"\n }\n }\n}\n
This method allows to retrieve Kura-related properties (derived from the kura.properties
file) and filter by their name. Available properties are listed in the table Kura properties.
/services/system/v1/properties/kura/filter
{\n \"names\": [\"kura.platform\", \"file.upload.size.max\", \"kura.have.net.admin\"]\n}\n
"},{"location":"references/rest-apis/rest-system-api/#responses_5","title":"Responses","text":"{\n \"kuraProperties\": {\n \"kura.platform\": \"aarch64\",\n \"kura.have.net.admin\": \"true\",\n \"file.upload.size.max\": \"-1\"\n }\n}\n
!wget https://raw.githubusercontent.com/mattdibi/eclipsecon-edgeAI-talk/master/notebook/train-data-raw.csv\n!wget https://raw.githubusercontent.com/mattdibi/eclipsecon-edgeAI-talk/master/notebook/train-data-raw.csv
--2022-10-18 15:32:34-- https://raw.githubusercontent.com/mattdibi/eclipsecon-edgeAI-talk/master/notebook/train-data-raw.csv\nResolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.110.133, 185.199.111.133, 185.199.108.133, ...\nConnecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.110.133|:443... connected.\nHTTP request sent, awaiting response... 200 OK\nLength: 13288126 (13M) [text/plain]\nSaving to: \u2018train-data-raw.csv.1\u2019\n\ntrain-data-raw.csv. 100%[===================>] 12,67M 4,56MB/s in 2,8s \n\n2022-10-18 15:32:38 (4,56 MB/s) - \u2018train-data-raw.csv.1\u2019 saved [13288126/13288126]\n\nIn\u00a0[2]: Copied!
!ls *.csv\n!ls *.csv
train-data-raw.csv\n
Let's start taking a look at the content of this dataset, we'll use pandas (Python Data Analysis library) for this.
In\u00a0[3]: Copied!import pandas as pd\n\nraw_data = pd.read_csv(\"./train-data-raw.csv\")\n\nraw_data.head()\nimport pandas as pd raw_data = pd.read_csv(\"./train-data-raw.csv\") raw_data.head() Out[3]: ID TIMESTAMP MAGNET_X TEMP_HUM_timestamp MAGNET_Z MAGNET_Y ACC_Y ACC_X GYRO_Y_timestamp ACC_Z ... PRESSURE_timestamp MAGNET_X_timestamp ACC_X_timestamp GYRO_Z_timestamp HUMIDITY_timestamp assetName ACC_Z_timestamp GYRO_X GYRO_Y GYRO_Z 0 1 1645778791786 -2.680372 1645778791413 5.036951 8.646852 0.004364 0.080122 1645778791413 0.984048 ... 1645778791413 1645778791413 1645778791413 1645778791413 1645778791413 asset-sensehat 1645778791413 0.053243 0.028920 0.036950 1 2 1645778792381 -3.110756 1645778792378 5.952562 10.521458 0.005091 0.080122 1645778792378 0.992090 ... 1645778792378 1645778792378 1645778792378 1645778792378 1645778792378 asset-sensehat 1645778792378 -0.051105 -0.028920 -0.037256 2 3 1645778793412 -3.482263 1645778793408 6.719675 11.944528 0.005334 0.080122 1645778793408 0.986729 ... 1645778793408 1645778793408 1645778793408 1645778793408 1645778793408 asset-sensehat 1645778793408 -0.025253 0.025560 0.038478 3 4 1645778794411 -3.813552 1645778794407 7.375115 13.093461 0.006061 0.080122 1645778794407 0.990384 ... 1645778794407 1645778794407 1645778794407 1645778794407 1645778794407 asset-sensehat 1645778794407 0.100695 -0.023422 -0.037867 4 5 1645778795411 -4.050513 1645778795407 7.854155 14.029530 0.004849 0.080607 1645778795407 0.988922 ... 1645778795407 1645778795407 1645778795407 1645778795407 1645778795407 asset-sensehat 1645778795407 -0.100389 0.021895 0.038172
5 rows \u00d7 29 columns
In\u00a0[4]: Copied!features = ['ACC_Y', 'ACC_X', 'ACC_Z',\n 'PRESSURE', 'TEMP_PRESS', 'TEMP_HUM',\n 'HUMIDITY', 'GYRO_X', 'GYRO_Y', 'GYRO_Z']\n\ndata = raw_data[features]\n\ndata.head()\nfeatures = ['ACC_Y', 'ACC_X', 'ACC_Z', 'PRESSURE', 'TEMP_PRESS', 'TEMP_HUM', 'HUMIDITY', 'GYRO_X', 'GYRO_Y', 'GYRO_Z'] data = raw_data[features] data.head() Out[4]: ACC_Y ACC_X ACC_Z PRESSURE TEMP_PRESS TEMP_HUM HUMIDITY GYRO_X GYRO_Y GYRO_Z 0 0.004364 0.080122 0.984048 992.322998 38.724998 40.330822 19.487146 0.053243 0.028920 0.036950 1 0.005091 0.080122 0.992090 992.288330 38.772915 40.385788 19.465750 -0.051105 -0.028920 -0.037256 2 0.005334 0.080122 0.986729 992.275635 38.795834 40.349144 19.572731 -0.025253 0.025560 0.038478 3 0.006061 0.080122 0.990384 992.279053 38.797916 40.330822 19.358767 0.100695 -0.023422 -0.037867 4 0.004849 0.080607 0.988922 992.333008 38.845833 40.385788 19.390862 -0.100389 0.021895 0.038172 In\u00a0[5]: Copied!
%matplotlib inline\nimport matplotlib.pyplot as plt\n\ndata.hist(bins=50, figsize=(20,15))\nplt.show()\n%matplotlib inline import matplotlib.pyplot as plt data.hist(bins=50, figsize=(20,15)) plt.show()
Note: Some of you might notice that this is a really simple dataset: some of the input data (like GYRO_*
and ACC_*
) do not change much over time. Such a dataset is not very challenging and a few, well-placed, thresholds might be sufficient to spot anomalous behaviour. For this tutorial we decided to keep things simple and easy to replicate. Anomalies can be simply triggered by moving the Raspberry Pi around.
Keep in mind that this approach is generic: any dataset from any appliance/connected device can be processed in the same way we're showing here. That's the magic of neural networks!
In\u00a0[6]: Copied!print(\"Data used in the Triton preprocessor\")\nprint(\"-----------Min-----------\")\nprint(data.min())\nprint(\"-----------Max-----------\")\nprint(data.max())\nprint(\"-------------------------\")\nprint(\"Data used in the Triton preprocessor\") print(\"-----------Min-----------\") print(data.min()) print(\"-----------Max-----------\") print(data.max()) print(\"-------------------------\")
Data used in the Triton preprocessor\n-----------Min-----------\nACC_Y -0.132551\nACC_X -0.049693\nACC_Z 0.759847\nPRESSURE 976.001709\nTEMP_PRESS 38.724998\nTEMP_HUM 40.220890\nHUMIDITY 13.003981\nGYRO_X -1.937896\nGYRO_Y -0.265019\nGYRO_Z -0.250647\ndtype: float64\n-----------Max-----------\nACC_Y 0.093099\nACC_X 0.150289\nACC_Z 1.177543\nPRESSURE 1007.996338\nTEMP_PRESS 46.093750\nTEMP_HUM 48.355824\nHUMIDITY 23.506138\nGYRO_X 1.923712\nGYRO_Y 0.219204\nGYRO_Z 0.671759\ndtype: float64\n-------------------------\nIn\u00a0[7]: Copied!
from sklearn.preprocessing import MinMaxScaler\n\nscaler = MinMaxScaler()\nscaled_data = scaler.fit_transform(data.to_numpy())\nfrom sklearn.preprocessing import MinMaxScaler scaler = MinMaxScaler() scaled_data = scaler.fit_transform(data.to_numpy()) In\u00a0[8]: Copied!
pd.DataFrame(scaled_data).describe()\npd.DataFrame(scaled_data).describe() Out[8]: 0 1 2 3 4 5 6 7 8 9 count 25278.000000 25278.000000 25278.000000 25278.000000 25278.000000 25278.000000 25278.000000 25278.000000 25278.000000 25278.000000 mean 0.603124 0.674196 0.550454 0.526446 0.605576 0.552252 0.466400 0.501160 0.545457 0.271295 std 0.049333 0.015135 0.031627 0.054050 0.288300 0.256587 0.176293 0.062908 0.067678 0.014665 min 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 25% 0.597087 0.667343 0.544924 0.481917 0.501060 0.441442 0.325637 0.501348 0.544670 0.270709 50% 0.603534 0.673413 0.551342 0.521377 0.655357 0.608108 0.511715 0.501841 0.547096 0.271685 75% 0.611055 0.680698 0.555426 0.552892 0.819339 0.734234 0.575212 0.502407 0.549386 0.272577 max 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 In\u00a0[9]: Copied!
from sklearn.model_selection import train_test_split\nimport numpy as np\n\nx_train, x_test = train_test_split(scaled_data, test_size=0.3, random_state=42)\nx_train = x_train.astype(np.float32)\nx_test = x_test.astype(np.float32)\nfrom sklearn.model_selection import train_test_split import numpy as np x_train, x_test = train_test_split(scaled_data, test_size=0.3, random_state=42) x_train = x_train.astype(np.float32) x_test = x_test.astype(np.float32) In\u00a0[10]: Copied!
import os\nos.environ['TF_CPP_MIN_LOG_LEVEL']='2' # Avoid AVX2 error\n\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import Input, Dense, Dropout\n\ndef create_model(input_dim):\n # The encoder will consist of a number of dense layers that decrease in size\n # as we taper down towards the bottleneck of the network, the latent space\n input_data = Input(shape=(input_dim,), name='INPUT0')\n\n # hidden layers\n encoder = Dense(9, activation='tanh', name='encoder_1')(input_data)\n encoder = Dropout(.15)(encoder)\n encoder = Dense(6, activation='tanh', name='encoder_2')(encoder)\n encoder = Dropout(.15)(encoder)\n\n # bottleneck layer\n latent_encoding = Dense(3, activation='linear', name='latent_encoding')(encoder)\n\n # The decoder network is a mirror image of the encoder network\n decoder = Dense(6, activation='tanh', name='decoder_1')(latent_encoding)\n decoder = Dropout(.15)(decoder)\n decoder = Dense(9, activation='tanh', name='decoder_2')(decoder)\n decoder = Dropout(.15)(decoder)\n\n # The output is the same dimension as the input data we are reconstructing\n reconstructed_data = Dense(input_dim, activation='linear', name='OUTPUT0')(decoder)\n\n autoencoder_model = Model(input_data, reconstructed_data)\n\n return autoencoder_model\nimport os os.environ['TF_CPP_MIN_LOG_LEVEL']='2' # Avoid AVX2 error from tensorflow.keras.models import Model from tensorflow.keras.layers import Input, Dense, Dropout def create_model(input_dim): # The encoder will consist of a number of dense layers that decrease in size # as we taper down towards the bottleneck of the network, the latent space input_data = Input(shape=(input_dim,), name='INPUT0') # hidden layers encoder = Dense(9, activation='tanh', name='encoder_1')(input_data) encoder = Dropout(.15)(encoder) encoder = Dense(6, activation='tanh', name='encoder_2')(encoder) encoder = Dropout(.15)(encoder) # bottleneck layer latent_encoding = Dense(3, activation='linear', name='latent_encoding')(encoder) # The decoder network is a mirror image of the encoder network decoder = Dense(6, activation='tanh', name='decoder_1')(latent_encoding) decoder = Dropout(.15)(decoder) decoder = Dense(9, activation='tanh', name='decoder_2')(decoder) decoder = Dropout(.15)(decoder) # The output is the same dimension as the input data we are reconstructing reconstructed_data = Dense(input_dim, activation='linear', name='OUTPUT0')(decoder) autoencoder_model = Model(input_data, reconstructed_data) return autoencoder_model In\u00a0[11]: Copied!
autoencoder_model = create_model(len(features))\nautoencoder_model.summary()\nautoencoder_model = create_model(len(features)) autoencoder_model.summary()
Model: \"model\"\n_________________________________________________________________\n Layer (type) Output Shape Param # \n=================================================================\n INPUT0 (InputLayer) [(None, 10)] 0 \n \n encoder_1 (Dense) (None, 9) 99 \n \n dropout (Dropout) (None, 9) 0 \n \n encoder_2 (Dense) (None, 6) 60 \n \n dropout_1 (Dropout) (None, 6) 0 \n \n latent_encoding (Dense) (None, 3) 21 \n \n decoder_1 (Dense) (None, 6) 24 \n \n dropout_2 (Dropout) (None, 6) 0 \n \n decoder_2 (Dense) (None, 9) 63 \n \n dropout_3 (Dropout) (None, 9) 0 \n \n OUTPUT0 (Dense) (None, 10) 100 \n \n=================================================================\nTotal params: 367\nTrainable params: 367\nNon-trainable params: 0\n_________________________________________________________________\nIn\u00a0[12]: Copied!
from tensorflow.keras import optimizers\n\nbatch_size = 32\nmax_epochs = 15\nlearning_rate = .0001\n\nopt = optimizers.Adam(learning_rate=learning_rate)\nautoencoder_model.compile(optimizer=opt, loss='mse', metrics=['accuracy'])\ntrain_history = autoencoder_model.fit(x_train, x_train,\n shuffle=True,\n epochs=max_epochs,\n batch_size=batch_size,\n validation_data=(x_test, x_test))\nfrom tensorflow.keras import optimizers batch_size = 32 max_epochs = 15 learning_rate = .0001 opt = optimizers.Adam(learning_rate=learning_rate) autoencoder_model.compile(optimizer=opt, loss='mse', metrics=['accuracy']) train_history = autoencoder_model.fit(x_train, x_train, shuffle=True, epochs=max_epochs, batch_size=batch_size, validation_data=(x_test, x_test))
Epoch 1/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.2282 - accuracy: 0.1129 - val_loss: 0.0922 - val_accuracy: 0.0045\nEpoch 2/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0949 - accuracy: 0.1541 - val_loss: 0.0279 - val_accuracy: 0.4210\nEpoch 3/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0613 - accuracy: 0.1779 - val_loss: 0.0206 - val_accuracy: 0.4426\nEpoch 4/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0466 - accuracy: 0.2152 - val_loss: 0.0186 - val_accuracy: 0.5276\nEpoch 5/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0366 - accuracy: 0.2514 - val_loss: 0.0157 - val_accuracy: 0.5944\nEpoch 6/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0290 - accuracy: 0.3083 - val_loss: 0.0119 - val_accuracy: 0.6403\nEpoch 7/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0228 - accuracy: 0.3930 - val_loss: 0.0078 - val_accuracy: 0.7182\nEpoch 8/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0186 - accuracy: 0.4668 - val_loss: 0.0059 - val_accuracy: 0.8195\nEpoch 9/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0157 - accuracy: 0.5021 - val_loss: 0.0048 - val_accuracy: 0.8256\nEpoch 10/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0136 - accuracy: 0.5277 - val_loss: 0.0042 - val_accuracy: 0.8263\nEpoch 11/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0121 - accuracy: 0.5409 - val_loss: 0.0037 - val_accuracy: 0.8296\nEpoch 12/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0107 - accuracy: 0.5569 - val_loss: 0.0036 - val_accuracy: 0.8306\nEpoch 13/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0098 - accuracy: 0.5857 - val_loss: 0.0034 - val_accuracy: 0.8256\nEpoch 14/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0089 - accuracy: 0.6076 - val_loss: 0.0033 - val_accuracy: 0.8281\nEpoch 15/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0083 - accuracy: 0.6337 - val_loss: 0.0032 - val_accuracy: 0.8262\nIn\u00a0[13]: Copied!
plt.plot(train_history.history['loss'])\nplt.plot(train_history.history['val_loss'])\nplt.legend(['loss on train data', 'loss on test data'])\nplt.plot(train_history.history['loss']) plt.plot(train_history.history['val_loss']) plt.legend(['loss on train data', 'loss on test data']) Out[13]:
<matplotlib.legend.Legend at 0x16d0c3400>
Here we can see the loss for the training set and the test set on the epochs.
Some of you might notice that this graph is somewhat unexpected. Why the validation loss is lower than the train loss? This is the effect of the regularization: regularization terms and dropout layer are affecting the network during training. A good writeup of this effect can be found here.
As an excercise try and compute the average MSE on the training set and the test set. You'll find that the MSE is lower in the training set!
We can now save the model on disk as we'll use this later.
In\u00a0[14]: Copied!autoencoder_model.save(\"./saved_model/autoencoder\")\nautoencoder_model.save(\"./saved_model/autoencoder\")
WARNING:absl:Function `_wrapped_model` contains input name(s) INPUT0 with unsupported characters which will be renamed to input0 in the SavedModel.\n
INFO:tensorflow:Assets written to: ./saved_model/autoencoder/assets\n
INFO:tensorflow:Assets written to: ./saved_model/autoencoder/assets\nIn\u00a0[15]: Copied!
!ls ./saved_model/autoencoder\n!ls ./saved_model/autoencoder
assets keras_metadata.pb saved_model.pb variables\nIn\u00a0[16]: Copied!
input_sample = x_test[3:4].copy() # Deep copy\n\nreconstructed_sample = autoencoder_model.predict(input_sample)\n\nprint(input_sample)\nprint(reconstructed_sample)\ninput_sample = x_test[3:4].copy() # Deep copy reconstructed_sample = autoencoder_model.predict(input_sample) print(input_sample) print(reconstructed_sample)
1/1 [==============================] - 0s 109ms/step\n[[0.603534 0.6770555 0.54900813 0.5327966 0.6680801 0.6171171\n 0.5198642 0.50135666 0.54716927 0.2718224 ]]\n[[0.59638697 0.67410123 0.5484349 0.52024144 0.64766663 0.5916597\n 0.4445051 0.499677 0.54471916 0.26904327]]\nIn\u00a0[17]: Copied!
import matplotlib.pyplot as plt\n\nindex = np.arange(10)\nbar_width = 0.35\n\nfigure, ax = plt.subplots()\n\ninbar = ax.bar(index, input_sample[0], bar_width, label=\"Input data\")\nrecbar = ax.bar(index+bar_width, reconstructed_sample[0], bar_width, label=\"Reconstruced data\")\n\nax.set_xlabel('Features')\nax.set_xticks(index + bar_width / 2)\nax.set_xticklabels(features, rotation = 45)\nax.legend()\nimport matplotlib.pyplot as plt index = np.arange(10) bar_width = 0.35 figure, ax = plt.subplots() inbar = ax.bar(index, input_sample[0], bar_width, label=\"Input data\") recbar = ax.bar(index+bar_width, reconstructed_sample[0], bar_width, label=\"Reconstruced data\") ax.set_xlabel('Features') ax.set_xticks(index + bar_width / 2) ax.set_xticklabels(features, rotation = 45) ax.legend() Out[17]:
<matplotlib.legend.Legend at 0x16d184880>
As we can see from the graph above it reconstructed the input fairly well. It is not perfect since the Autoencoder is lossy but it is good enough
What happens if we manipulate this sample in a way the autoencoder doesn't expect (i.e. we introduce an anomaly)?
Let's try and set the ACC_Z
to a value the autoencoder has never seen before.
input_anomaly = input_sample.copy() # Deep copy\n\ninput_anomaly[0][2] = 0.15\n\nreconstructed_anomaly = autoencoder_model.predict(input_anomaly)\n\nprint(input_anomaly)\nprint(reconstructed_anomaly)\ninput_anomaly = input_sample.copy() # Deep copy input_anomaly[0][2] = 0.15 reconstructed_anomaly = autoencoder_model.predict(input_anomaly) print(input_anomaly) print(reconstructed_anomaly)
1/1 [==============================] - 0s 21ms/step\n[[0.603534 0.6770555 0.15 0.5327966 0.6680801 0.6171171\n 0.5198642 0.50135666 0.54716927 0.2718224 ]]\n[[0.60162103 0.69035804 0.55594885 0.51874125 0.7346029 0.6700014\n 0.40932336 0.5034408 0.5424664 0.26861513]]\nIn\u00a0[19]: Copied!
figure, ax = plt.subplots()\n\ninbar = ax.bar(index, input_anomaly[0], bar_width, label=\"Input anomaly\")\nrecbar = ax.bar(index+bar_width, reconstructed_anomaly[0], bar_width, label=\"Reconstruced anomaly\")\n\nax.set_xlabel('Features')\nax.set_xticks(index + bar_width / 2)\nax.set_xticklabels(features, rotation = 45)\nax.legend()\nfigure, ax = plt.subplots() inbar = ax.bar(index, input_anomaly[0], bar_width, label=\"Input anomaly\") recbar = ax.bar(index+bar_width, reconstructed_anomaly[0], bar_width, label=\"Reconstruced anomaly\") ax.set_xlabel('Features') ax.set_xticks(index + bar_width / 2) ax.set_xticklabels(features, rotation = 45) ax.legend() Out[19]:
<matplotlib.legend.Legend at 0x16d3c0220>
The autoencoder fails to reconstruct the data it received at the input. This means that the reconstruction error is very high.
In\u00a0[20]: Copied!from sklearn.metrics import mean_squared_error\n\nprint(\"Anomaly %f\"% mean_squared_error(input_anomaly[0], reconstructed_anomaly[0]))\nprint(\"Normal %f\"% mean_squared_error(input_sample[0], reconstructed_sample[0]))\nfrom sklearn.metrics import mean_squared_error print(\"Anomaly %f\"% mean_squared_error(input_anomaly[0], reconstructed_anomaly[0])) print(\"Normal %f\"% mean_squared_error(input_sample[0], reconstructed_sample[0]))
Anomaly 0.018465\nNormal 0.000698\n
It's working as expected!
We now need to decide when to trigger an alarm (i.e. classify an input sample as anomalous) from this reconstruction error. In other words we need to decide our threshold.
There are multiple ways to set this value, in this example we'll use the Z-Score.
From Wikipedia:
In statistics, the standard score is the number of standard deviations by which the value of a raw score (i.e., an observed value or data point) is above or below the mean value of what is being observed or measured.[...]
It is calculated by subtracting the population mean from an individual raw score and then dividing the difference by the population standard deviation.
We'll consider a sample an anomaly if the Reconstruction Error Z-Score is not in the range [-2, +2]. This means that if the reconstruction error for a sample is more than 2 standard deviation away from the average reconstruction error computed on the test set, the sample is an anomaly. This choice is arbirtary, we can control the sensitivity of the detector by changing this range.
In\u00a0[21]: Copied!x_test_recon = autoencoder_model.predict(x_test)\nreconstruction_scores = np.mean((x_test - x_test_recon)**2, axis=1) # MSE\n\nreconstruction_scores_pd = pd.DataFrame({'recon_score': reconstruction_scores})\nprint(reconstruction_scores_pd.describe())\nx_test_recon = autoencoder_model.predict(x_test) reconstruction_scores = np.mean((x_test - x_test_recon)**2, axis=1) # MSE reconstruction_scores_pd = pd.DataFrame({'recon_score': reconstruction_scores}) print(reconstruction_scores_pd.describe())
237/237 [==============================] - 0s 620us/step\n recon_score\ncount 7584.000000\nmean 0.003175\nstd 0.005438\nmin 0.000098\n25% 0.000816\n50% 0.001211\n75% 0.002108\nmax 0.106237\nIn\u00a0[22]: Copied!
def z_score(mse_sample):\n return (mse_sample - reconstruction_scores_pd.mean())/reconstruction_scores_pd.std()\ndef z_score(mse_sample): return (mse_sample - reconstruction_scores_pd.mean())/reconstruction_scores_pd.std() In\u00a0[23]: Copied!
mse_anomaly = mean_squared_error(input_anomaly[0], reconstructed_anomaly[0])\nmse_normal = mean_squared_error(input_sample[0], reconstructed_sample[0])\n\nz_score_anomaly = z_score(mse_anomaly)\nz_score_normal = z_score(mse_normal)\n\nprint(\"Anomaly Z-score %f\"% z_score_anomaly)\nprint(\"Normal Z-score %f\"% z_score_normal)\nmse_anomaly = mean_squared_error(input_anomaly[0], reconstructed_anomaly[0]) mse_normal = mean_squared_error(input_sample[0], reconstructed_sample[0]) z_score_anomaly = z_score(mse_anomaly) z_score_normal = z_score(mse_normal) print(\"Anomaly Z-score %f\"% z_score_anomaly) print(\"Normal Z-score %f\"% z_score_normal)
Anomaly Z-score 2.811887\nNormal Z-score -0.455488\n
We now have our anomaly detector... let's see how we can deploy it on our Kura\u2122-powered edge device.
In\u00a0[24]: Copied!!rm -rf ./tf_autoencoder_fp32/ && mkdir -p ./tf_autoencoder_fp32/1\n!rm -rf ./tf_autoencoder_fp32/ && mkdir -p ./tf_autoencoder_fp32/1 In\u00a0[25]: Copied!
!ls\n!ls
AD-EdgeAI.ipynb requirements.txt train-data-raw.csv\nREADME.md saved_model train-data-raw.csv.1\nimgs tf_autoencoder_fp32\nIn\u00a0[26]: Copied!
cp -r ./saved_model/autoencoder tf_autoencoder_fp32/1/model.savedmodel\ncp -r ./saved_model/autoencoder tf_autoencoder_fp32/1/model.savedmodel In\u00a0[27]: Copied!
!tree tf_autoencoder_fp32\n!tree tf_autoencoder_fp32
tf_autoencoder_fp32\n\u2514\u2500\u2500 1\n \u2514\u2500\u2500 model.savedmodel\n \u251c\u2500\u2500 assets\n \u251c\u2500\u2500 keras_metadata.pb\n \u251c\u2500\u2500 saved_model.pb\n \u2514\u2500\u2500 variables\n \u251c\u2500\u2500 variables.data-00000-of-00001\n \u2514\u2500\u2500 variables.index\n\n4 directories, 4 files\n
Now comes the hard part: we need to provide the model configuration (i.e. the config.pbtxt
file). In the case of the autoencoder is pretty simple:
name: \"tf_autoencoder_fp32\"\nbackend: \"tensorflow\"\nmax_batch_size: 0\ninput [\n {\n name: \"INPUT0\"\n data_type: TYPE_FP32\n dims: [ 1, 10 ]\n }\n]\noutput [\n {\n name: \"OUTPUT0\"\n data_type: TYPE_FP32\n dims: [ -1, 10 ]\n }\n]\nversion_policy: { all { }}\ninstance_group [{ kind: KIND_CPU }]\n
Each model input
and output
must specify the name
, data_type
and dims
. We already know all of these:
name
: corresponds to the layer name we've seen in the Model Training section. INPUT0
for the input and OUTPUT0
for the output.data_type
: will be float since we didn't perform any quantizationdims
: is the shape of the in/out tensor. In this case it will correspond to an array with the same length as the number of features.Other interesting parameters of this configuration are:
backend
: where we set the backend for the model. In this case it will be the Tensorflow backendname
: the name of the model that must correspond to the name of the folderinstance_group
: where we set where we want the model to run. In this case we'll use the CPU since we're on a Raspberry Pi but keep in mind that Triton support multiple accelerators.for a deep dive into the model configuration parameter take a look at the official documentation.
"},{"location":"tutorials/AD-EdgeAI/#edge-ai-anomaly-detection","title":"Edge AI Anomaly Detection\u00b6","text":""},{"location":"tutorials/AD-EdgeAI/#overview","title":"Overview\u00b6","text":"This document contains the code and the instructions for our EclipseCON 2022 Talk: \"How to Train Your Dragon and Its Friends: AI on the Edge with Eclipse Kura\u2122\"
This notebook can also be viewed and ran on Google Colab.
In this example scenario we will collect the data provided by a Raspberry Pi Sense HAT using Eclipse Kura\u2122 and upload them to a Eclipse Kapua\u2122 instance. We will then download this data and train an AI-based anomaly detector using TensorFlow. Finally we will deploy the trained anomaly detector model leveraging Nvidia Triton\u2122 Inference Server and Eclipse Kura\u2122 integration.
We'll subdivide this example scenario in three main sections:
In this setup we'll leverage Eclipe Kura\u2122 and Kapua\u2122 for retrieving data from a Raspberry Pi Sense HAT and upload them to the cloud.
The Sense HAT is an add-on board for Raspberry Pi which provides an 8\u00d78 RGB LED matrix, a five-button joystick and includes the following sensors:
Requirement: A Raspberry Pi 3/4 running the latest version of Raspberry Pi OS 64 bit.
To make everything work on the Raspberry Pi we need to use the develop
version of the raspberry-pi-ubuntu-20-nn
Kura installer (yes, I know we're installing the Ubuntu package on the Raspberry Pi OS but bear with me...) . You can do so by downloading the repo and building locally or by downloading a pre-built installer from the Kura CI artifacts.
Copy the resulting file kura_<version>_raspberry-pi-ubuntu-20_installer-nn.deb
on the target device.
On the target device run the following commands:
sudo apt-get install -y wget apt-transport-https gnupg\n
sudo wget -O - https://packages.adoptium.net/artifactory/api/gpg/key/public | sudo apt-key add -\n
sudo echo \"deb https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main\" | sudo tee /etc/apt/sources.list.d/adoptium.list\n
sudo apt-get update && sudo apt-get install temurin-8-jdk chrony\n
Finally install Kura with:
sudo apt install ./kura_<version>_raspberry-pi-ubuntu-20_installer-nn.deb\n"},{"location":"tutorials/AD-EdgeAI/#cloud-connection","title":"Cloud connection\u00b6","text":"
After setting up an Eclipse Kura\u2122 instance on the Raspberry Pi we'll need to connect it to an Eclipse Kapua\u2122 instance.
An excellent tutorial on how to deploy a Kapua\u2122 instance using Docker is available in the official repository. For the purpose of this tutorial we'll assume a Kapua\u2122 instance is already running and is available for connection from Kura\u2122
After setting up the Kapua\u2122 instance you can refer to the official Kura\u2122 documentation for connecting the Raspberry Pi to the Kapua\u2122 instance. For the remaining of this tutorial we'll assume a connection with the Kapua\u2122 was correctly established.
"},{"location":"tutorials/AD-EdgeAI/#data-publisher","title":"Data publisher\u00b6","text":"To publish the collected data on the Cloud we'll need to create a new Cloud Publisher through the Kura\u2122 web interface. Go to \"Cloud Connections\" and press \"New Pub/Sub\", in the example below we'll call our new publisher KapuaSenseHatPublisher
.
To keep things clean we'll create a new topic called SenseHat
. To do so we'll move to the KapuaSenseHatPublisher
configuration and we'll update the Application Topic
field to A1/SenseHat
Kura\u2122 provides a driver that allows to interact to a RaspberryPi SenseHat device using Kura Driver, Asset and Wires frameworks.
From the Kura\u2122 documentation:
Eclipse Kura introduces a model based on the concepts of Drivers and Assets to simplify the communication with the field devices attached to a gateway.
A Driver encapsulates the communication protocol and its configuration parameters, dealing with the low-level characteristics of the field protocol. It opens, closes and performs the communication with the end field device. It also exposes field protocol specific information that can be used by upper levels of abstraction to simplify the interaction with the end devices.
An Asset is a logical representation of a field device, described by a list of Channels. The Asset uses a specific Driver instance to communicate with the underlying device and it models a generic device resource as a Channel. A register in a PLC or a GATT Characteristic in a Bluetooth device are examples of Channels. In this way, each Asset has multiple Channels for reading and writing data from/to an Industrial Device.
The Kura Sense Hat driver requires a few changes on the Raspberry Pi:
sudo raspi-config
As others Drivers supported by Kura, it is distributed as a deployment package on the Eclipse Marketplace. It consists of two packages:
We need to install both. Complete installation instructions are available here.
"},{"location":"tutorials/AD-EdgeAI/#driver-configuration","title":"Driver configuration\u00b6","text":"We now need to configure the driver to access the sensors on the SenseHat. Move to the \"Driver and Assets\" section of the web UI and create a new driver. We'll call it driver-sensehat
.
Then add a new Asset (which we'll call asset-sensehat
) to this driver and configure it as per the screenshots below. We'll need a Channel for every sensor we want to access.
Refer to the following table for the driver parameters:
name type value.type resource ACC_X READ FLOAT ACCELERATION_X ACC_Y READ FLOAT ACCELERATION_Y ACC_Z READ FLOAT ACCELERATION_Z GYRO_X READ FLOAT GYROSCOPE_X GYRO_Y READ FLOAT GYROSCOPE_Y GYRO_Z READ FLOAT GYROSCOPE_Z HUMIDITY READ FLOAT HUMIDITY PRESSURE READ FLOAT PRESSURE TEMP_HUM READ FLOAT TEMPERATURE_FROM_HUMIDITY TEMP_PRESS READ FLOAT TEMPERATURE_FROM_PRESSUREAfter correctly configuring it you should see the data in the \"Data\" page of the UI.
"},{"location":"tutorials/AD-EdgeAI/#wire-graph","title":"Wire graph\u00b6","text":"Now that we have our Driver and Cloud Publisher ready we can put everything together with a Kura Wire Graph.
From Kura\u2122 documentation:
The Kura\u2122 Wires feature aims to simplify the development of IoT Edge Computing Applications leveraging reusable configurable components that can be wired together and which, eventually, allows configurable cooperation between these components.
In the dataflow programming model, the application logic is expressed as a directed graph (flow) where each node can have inputs, outputs, and independent processing units. There are nodes that only produce outputs and ones that only consume inputs, which usually represent the start and the end of the flow. The inner-graph nodes process the inputs and produce outputs for downstream nodes. The processing unit of a node executes independently and does not affect the execution of other nodes. Thus, the nodes are highly reusable and portable.
Move to the \"Wire Graph\" section of the UI. We'll need a graph with three components:
Timer
which will dictate the sample rate at which we will collect data coming from the Sense HatWireAsset
for the Sense Hat driver assetPublisher
for the Kapua publisher we created before.The resulting Wire Graph will look like this:
"},{"location":"tutorials/AD-EdgeAI/#timer","title":"Timer\u00b6","text":"Configure the timer such that it will poll the SenseHat each second, this can be done by setting the simple.interval
to 1
.
Select the driver-sensehat
when creating the WireAsset. No further configuration is needed for this component.
Create a \"Publisher\" Wire component and select the KapuaSensehatPublisher
from the target filter.
Don't forget to press \"Apply\" to start the Wire Graph!
"},{"location":"tutorials/AD-EdgeAI/#collect-the-data","title":"Collect the data\u00b6","text":"At this point you should see data coming from the Rasperry Pi from the Kapua\u2122 console under the SenseHat
topic.
You can download the .csv
file directly from the console using the \"Export to CSV\" button.
We will now use the data collected in the previous section to train an artificial neural network-based Anomaly Detector of our design. To this end we will use an Autoencoder model. To understand why we choose such model we need to understand how it works. From Wikipedia:
An autoencoder is a type of artificial neural network used to learn efficient codings of unlabeled data (unsupervised learning). The encoding is validated and refined by attempting to regenerate the input from the encoding. The autoencoder learns a representation (encoding) for a set of data, typically for dimensionality reduction, by training the network to ignore insignificant data (\u201cnoise\u201d).
Another application for autoencoders is anomaly detection. By learning to replicate the most salient features in the training data [...] the model is encouraged to learn to precisely reproduce the most frequently observed characteristics. When facing anomalies, the model should worsen its reconstruction performance. In most cases, only data with normal instances are used to train the autoencoder; in others, the frequency of anomalies is small compared to the observation set so that its contribution to the learned representation could be ignored. After training, the autoencoder will accurately reconstruct \"normal\" data, while failing to do so with unfamiliar anomalous data. Reconstruction error (the error between the original data and its low dimensional reconstruction) is used as an anomaly score to detect anomalies
In simple terms:
Why did we choose this approach over others?
We can now work on our .csv
file downloaded from Kapua. For demonstration purposes an already available dataset is provided within this repository.
If you're running this notebook through Google Colab you'll need to download the dataset running the cell below:
"},{"location":"tutorials/AD-EdgeAI/#feature-selection","title":"Feature selection\u00b6","text":"As you might notice there's some information in the dataset we don't care about and are not meaningful for our application:
ID
timestamps
assetName
which doesn't changeThen we can remove them from the dataset.
"},{"location":"tutorials/AD-EdgeAI/#feature-scaling","title":"Feature scaling\u00b6","text":"AI models don't perform well when the input numerical attributes have very different scales. As you can see ACC_X
, ACC_Y
and ACC_Z
range from 0 to 1, while the PRESSURE
have far higher values.
There are two common ways to address this: normalization and standardization.
Normalization (a.k.a. Min-max scaling) shifts and rescales values so that they end up ranging from 0 to 1. This can be done by subtracting the min value and dividing by the max minus the min.
x' = $\\frac{x - min(x)}{max(x) - min(x)}$
Standardization makes the values of each feature in the data have zero-mean (when subtracting the mean in the numerator) and unit-variance. The general method of calculation is to determine the distribution mean and standard deviation for each feature. Next we subtract the mean from each feature. Then we divide the values (mean is already subtracted) of each feature by its standard deviation.
x' = $\\frac{x - avg(x)}{\\sigma}$
Fortunately for us scikit-learn library provides a function for both of them. In this case we'll use normalization because it works well for this application.
"},{"location":"tutorials/AD-EdgeAI/#train-test-split","title":"Train test split\u00b6","text":"The only way to know how well a model will generalize to new data points is to try it on new data. To do so we split our data into two sets: the training set and the test set.
To do so we'll use a function from scikit-learn
.
We can now leverage the Keras API of Tensorflow for creating our Autoencoder and then train it on our dataset.
We'll design a neural network architecture such that we impose a bottleneck in the network which forces a compressed knowledge representation of the original input (also called the latent-space representation). If the input features were each independent of one another, this compression and subsequent reconstruction would be a very difficult task. However, if some sort of structure exists in the data (ie. correlations between input features), this structure can be learned and consequently leveraged when forcing the input through the network's bottleneck.
The bottleneck consists of reducing the number of neurons for each layer of the neural network up to a certain point, and then increase the number until the original input number is reached. This will result in a hourglass shape which is typical for the Autoencoders.
"},{"location":"tutorials/AD-EdgeAI/#build-the-autoencoder-model","title":"Build the Autoencoder model\u00b6","text":"In this example we'll use a basic fully-connected autoencoder but keep in mind that autoencoders can be built with different classes of neural network (i.e. Convolutional Neural Networks, Recurrent Neural Networks etc).
"},{"location":"tutorials/AD-EdgeAI/#model-training","title":"Model training\u00b6","text":"As we already explained, the autoencoder is a type of artificial neural network used to learn efficient codings of unlabeled data. We'll use that to reconstruct the input at the output. To train an autoencoder we don\u2019t need to do anything fancy, just throw the raw input data at it. Autoencoders are considered an unsupervised learning technique since they don\u2019t need explicit labels to train on but to be more precise they are self-supervised because they generate their own labels from the training data.
To train our neural network we need to have a performance metric to measure how well it is learning to reconstruct the data i.e. our loss function. The loss function in our example, which we need to minimize during our training, is the error between the input data and the data reconstructed by the autoencoder. We'll use the Mean Squared Error.
MSE = $\\frac{1}{n}\\sum_{i=1}^{n}{(Y_i - Y'_i)^2}$
Where:
Before starting the training we need to set the hyperparameters). Hyperparameters are parameters whose values control the learning process and determine the values of model parameters that a learning algorithm ends up learning. These are the learning_rate
, max_epochs
, optimizer
and the batch_size
you see in the code snippet below. You may ask yourself how to set them, it all comes down to trial and error. Try tweaking them below and see how they affect the learning process...
A good explaination of their meaning can be found in the Keras documentation.
"},{"location":"tutorials/AD-EdgeAI/#model-evaluation","title":"Model evaluation\u00b6","text":"We now have a model that reconstruct the input at the output... doesn't sounds really useful right?
Let's see it in action. Let's take a sample from the test set and run it through our autoencoder.
"},{"location":"tutorials/AD-EdgeAI/#model-deployment","title":"Model deployment\u00b6","text":"To deploy our model on the target device we'll leverage Kura\u2122's newly added Nvidia\u2122 Triton Inferece Server integration.
The Nvidia\u2122 Triton Inference Server is an open-source inference service software that enables the user to deploy trained AI models from any framework on GPU or CPU infrastructure. It supports all major frameworks like TensorFlow, TensorRT, PyTorch, ONNX Runtime, and even custom framework backend. With specific backends, it is also possible to run Python scripts, mainly for pre-and post-processing purposes, and exploit the DALI building block for optimized operations.
For installation refer to the official Kura\u2122 and Triton documentation. For the rest of this tutorial we'll assume a Triton container is available on the target device. It can be simply installed with:
docker pull nvcr.io/nvidia/tritonserver:22.07-tf2-python-py3\n
We'll also need to install Kura\u2122's Triton bundles:
The first step in using Triton to serve your models is to place one or more models into a model repository i.e. a folder were the model are available for Triton to load. Depending on the type of the model and on what Triton capabilities you want to enable for the model, you may need to create a model configuration for the model. This configuration is a protobuf containing informations about runtime configuration and input/output shape accepted by the model.
For our autoencoder model we'll need three \"models\":
To simplify the handling of these models and improve inference performance, we'll use an advanced feature of Triton wich is an Ensemble Model. From Triton official documentation:
An ensemble model represents a pipeline of one or more models and the connection of input and output tensors between those models. Ensemble models are intended to be used to encapsulate a procedure that involves multiple models, such as \"data preprocessing -> inference -> data postprocessing\". Using ensemble models for this purpose can avoid the overhead of transferring intermediate tensors and minimize the number of requests that must be sent to Triton.
"},{"location":"tutorials/AD-EdgeAI/#autoencoder","title":"Autoencoder\u00b6","text":"As seen in the \"Model training\" section, our model is available as a Tensorflow SavedModel which can be simply loaded by the Triton Tensorflow backend. We just need to configure it properly.
We'll start by creating the following folder structure
tf_autoencoder_fp32\n\u251c\u2500\u2500 1\n\u2502 \u2514\u2500\u2500 model.savedmodel\n\u2502 \u251c\u2500\u2500 assets\n\u2502 \u251c\u2500\u2500 keras_metadata.pb\n\u2502 \u251c\u2500\u2500 saved_model.pb\n\u2502 \u2514\u2500\u2500 variables\n\u2502 \u251c\u2500\u2500 variables.data-00000-of-00001\n\u2502 \u2514\u2500\u2500 variables.index\n\u2514\u2500\u2500 config.pbtxt\n
This can be done by copying the model we saved in the Model Training section:
"},{"location":"tutorials/AD-EdgeAI/#preprocessor","title":"Preprocessor\u00b6","text":"As discussed in the \"Data processing\" section, before providing the incoming data to the autoencoder, we need to perform feature selection and scaling. In addition to these responsibilites, the Preprocessor will need to perform a sort of serialization of the data to comply to the input shape accepted by the Autoencoder. This is due to how Kura manages the data running on Wires. More details can be found here.
To perform all of this we'll use the Python backend available in Triton.
As described in the previous section we will need to provide the following folder structure:
preprocessor\n\u251c\u2500\u2500 1\n\u2502 \u2514\u2500\u2500 model.py\n\u2514\u2500\u2500 config.pbtxt\n
"},{"location":"tutorials/AD-EdgeAI/#preprocessor-configuration","title":"Preprocessor Configuration\u00b6","text":"As discussed in the official Kura documentation:
The AI wire component takes a WireEnvelope as an input, it processes its records and feeds them to the specified preprocessing or inference model.
...
The models that manage the input and the output must expect a list of inputs such that:
WireRecord
properties[1]
Therefore for our input
we'll have that each name corresponds to the names we've seen in the Data Collection section. The output
needs to correspond to the input accepted by the model (i.e. INPUT0
).
name: \"preprocessor\"\nbackend: \"python\"\n\ninput [\n {\n name: \"ACC_X\"\n data_type: TYPE_FP32\n dims: [ 1 ]\n }\n]\ninput [\n {\n name: \"ACC_Y\"\n data_type: TYPE_FP32\n dims: [ 1 ]\n }\n]\n ...\ninput [\n {\n name: \"TEMP_PRESS\"\n data_type: TYPE_FP32\n dims: [ 1 ]\n }\n]\noutput [\n {\n name: \"INPUT0\"\n data_type: TYPE_FP32\n dims: [ 1, 10 ]\n }\n]\ninstance_group [{ kind: KIND_CPU }]\n"},{"location":"tutorials/AD-EdgeAI/#preprocessor-model","title":"Preprocessor Model\u00b6","text":"
As we've seen in the Data Processing section the Preprocessor is responsible for scaling the input features and serializing them in the tensor shape expected by the Autoencoder model.
This can be done with the following python script:
import numpy as np\nimport json\n\nimport triton_python_backend_utils as pb_utils\n\n\nclass TritonPythonModel:\n\n def initialize(self, args):\n self.model_config = model_config = json.loads(args['model_config'])\n\n output0_config = pb_utils.get_output_config_by_name(\n model_config, \"INPUT0\")\n\n self.output0_dtype = pb_utils.triton_string_to_numpy(\n output0_config['data_type'])\n\n def execute(self, requests):\n output0_dtype = self.output0_dtype\n\n responses = []\n\n for request in requests:\n acc_x = pb_utils.get_input_tensor_by_name(request, \"ACC_X\").as_numpy()\n acc_y = pb_utils.get_input_tensor_by_name(request, \"ACC_Y\").as_numpy()\n acc_z = pb_utils.get_input_tensor_by_name(request, \"ACC_Z\").as_numpy()\n gyro_x = pb_utils.get_input_tensor_by_name(request, \"GYRO_X\").as_numpy()\n gyro_y = pb_utils.get_input_tensor_by_name(request, \"GYRO_Y\").as_numpy()\n gyro_z = pb_utils.get_input_tensor_by_name(request, \"GYRO_Z\").as_numpy()\n humidity = pb_utils.get_input_tensor_by_name(request, \"HUMIDITY\").as_numpy()\n pressure = pb_utils.get_input_tensor_by_name(request, \"PRESSURE\").as_numpy()\n temp_hum = pb_utils.get_input_tensor_by_name(request, \"TEMP_HUM\").as_numpy()\n temp_press = pb_utils.get_input_tensor_by_name(request, \"TEMP_PRESS\").as_numpy()\n\n out_0 = np.array([acc_y, acc_x, acc_z, pressure, temp_press, temp_hum, humidity, gyro_x, gyro_y, gyro_z]).transpose()\n\n # ACC_Y ACC_X ACC_Z PRESSURE TEMP_PRESS TEMP_HUM HUMIDITY GYRO_X GYRO_Y GYRO_Z\n min = np.array([-0.132551, -0.049693, 0.759847, 976.001709, 38.724998, 40.220890, 13.003981, -1.937896, -0.265019, -0.250647])\n max = np.array([ 0.093099, 0.150289, 1.177543, 1007.996338, 46.093750, 48.355824, 23.506138, 1.923712, 0.219204, 0.671759])\n\n # MinMax scaling\n out_0_scaled = (out_0 - min)/(max - min)\n\n # Create output tensor\n out_tensor_0 = pb_utils.Tensor(\"INPUT0\",\n out_0_scaled.astype(output0_dtype))\n\n inference_response = pb_utils.InferenceResponse(\n output_tensors=[out_tensor_0])\n responses.append(inference_response)\n\n return responses\n
Here there are two important things to note:
min
and max
arrays we found in the Data Processing section but we could have serialized the MinMaxScaler
using pickle
instead.As discussed in the \"Data processing\" section, to perform the anomaly detection step we need to compute the Mean Squared Error between the recontructed data and the actual input data. Due to this the configuration of the Postprocessor model will be somewhat more complicated than before: in addition to the output of the Autoencoder model we will need the output of the Preprocessor model.
To perform all of this we'll use the Python backend again.
As described in the previous section we will need to provide the following folder structure:
postprocessor\n\u251c\u2500\u2500 1\n\u2502 \u2514\u2500\u2500 model.py\n\u2514\u2500\u2500 config.pbtxt\n
"},{"location":"tutorials/AD-EdgeAI/#postprocessor-configuration","title":"Postprocessor Configuration\u00b6","text":"name: \"postprocessor\"\nbackend: \"python\"\n\ninput [\n {\n name: \"RECONSTR0\"\n data_type: TYPE_FP32\n dims: [ 1, 10 ]\n }\n]\ninput [\n {\n name: \"ORIG0\"\n data_type: TYPE_FP32\n dims: [ 1, 10 ]\n }\n]\noutput [\n {\n name: \"ANOMALY_SCORE0\"\n data_type: TYPE_FP32\n dims: [ 1 ]\n }\n]\noutput [\n {\n name: \"ANOMALY0\"\n data_type: TYPE_BOOL\n dims: [ 1 ]\n }\n]\ninstance_group [{ kind: KIND_CPU }]\n
As we can see we have two inputs and two outputs:
Let's see how this is computed by the Python model.
"},{"location":"tutorials/AD-EdgeAI/#postprocessor-model","title":"Postprocessor Model\u00b6","text":"import numpy as np\nimport json\n\nimport triton_python_backend_utils as pb_utils\n\ndef z_score(mse):\n return (mse - MEAN_MSE)/STD_MSE\n\n\nclass TritonPythonModel:\n\n def initialize(self, args):\n self.model_config = model_config = json.loads(args['model_config'])\n\n output0_config = pb_utils.get_output_config_by_name(\n model_config, \"ANOMALY_SCORE0\")\n output1_config = pb_utils.get_output_config_by_name(\n model_config, \"ANOMALY0\")\n\n self.output0_dtype = pb_utils.triton_string_to_numpy(\n output0_config['data_type'])\n self.output1_dtype = pb_utils.triton_string_to_numpy(\n output1_config['data_type'])\n\n def execute(self, requests):\n output0_dtype = self.output0_dtype\n output1_dtype = self.output1_dtype\n\n responses = []\n\n for request in requests:\n # Get input\n x_recon = pb_utils.get_input_tensor_by_name(request, \"RECONSTR0\").as_numpy()\n x_orig = pb_utils.get_input_tensor_by_name(request, \"ORIG0\").as_numpy()\n\n # Get Mean square error between reconstructed input and original input\n reconstruction_score = np.mean((x_orig - x_recon)**2, axis=1)\n \n #\u00a0Z-Score of Mean square error must be inside [-2; 2]\n anomaly = np.array([z_score(reconstruction_score) < -2.0 or z_score(reconstruction_score) > 2.0])\n\n # Create output tensors\n out_tensor_0 = pb_utils.Tensor(\"ANOMALY_SCORE0\",\n reconstruction_score.astype(output0_dtype))\n out_tensor_1 = pb_utils.Tensor(\"ANOMALY0\",\n anomaly.astype(output1_dtype))\n\n inference_response = pb_utils.InferenceResponse(\n output_tensors=[out_tensor_0, out_tensor_1])\n responses.append(inference_response)\n\n return responses\n
As you can see the script is simple:
Note: MEAN_MSE
and STD_MSE
are the mean value and the standard deviation of the Mean Squared Error computed on the test set and correspond to the reconstruction_scores_pd.mean()
and reconstruction_scores_pd.std()
we used in the previous section. We didn't set them as they change for every training performed on the Autoencoder. Be sure to set it to their proper values before trying this model on the Triton server!
To make things easier for ourselves and improve performance we'll consolidate the AI pipeline into an Ensemble Model.
We will need to provide the following folder structure:
ensemble_pipeline\n\u251c\u2500\u2500 1\n\u2514\u2500\u2500 config.pbtxt\n
Note that the 1
folder is empty. The ensemble model essentially describe how to connect the models that belong to the processing pipeline.
Therefore we'll need to focus on the configuration only.
name: \"ensemble_pipeline\"\nplatform: \"ensemble\"\nmax_batch_size: 0\ninput [\n {\n name: \"ACC_X\"\n data_type: TYPE_FP32\n dims: [ 1 ]\n }\n]\ninput [\n {\n name: \"ACC_Y\"\n data_type: TYPE_FP32\n dims: [ 1 ]\n }\n]\n ...\ninput [\n {\n name: \"TEMP_PRESS\"\n data_type: TYPE_FP32\n dims: [ 1 ]\n }\n]\noutput [\n {\n name: \"ANOMALY_SCORE0\"\n data_type: TYPE_FP32\n dims: [ 1 ]\n }\n]\noutput [\n {\n name: \"ANOMALY0\"\n data_type: TYPE_BOOL\n dims: [ 1 ]\n }\n]\nensemble_scheduling {\n step [\n {\n model_name: \"preprocessor\"\n model_version: -1\n input_map{\n key: \"ACC_X\"\n value: \"ACC_X\"\n }\n input_map{\n key: \"ACC_Y\"\n value: \"ACC_Y\"\n }\n ...\n input_map{\n key: \"TEMP_PRESS\"\n value: \"TEMP_PRESS\"\n }\n output_map {\n key: \"INPUT0\"\n value: \"preprocess_out\"\n }\n },\n {\n model_name: \"tf_autoencoder_fp32\"\n model_version: -1\n input_map {\n key: \"INPUT0\"\n value: \"preprocess_out\"\n }\n output_map {\n key: \"OUTPUT0\"\n value: \"autoencoder_output\"\n }\n },\n {\n model_name: \"postprocessor\"\n model_version: -1\n input_map {\n key: \"RECONSTR0\"\n value: \"autoencoder_output\"\n }\n input_map {\n key: \"ORIG0\"\n value: \"preprocess_out\"\n }\n output_map {\n key: \"ANOMALY_SCORE0\"\n value: \"ANOMALY_SCORE0\"\n }\n output_map {\n key: \"ANOMALY0\"\n value: \"ANOMALY0\"\n }\n }\n ]\n}\n
The configuration is split in two main parts:
To better visualize the configuration we can look at the graph below.
"},{"location":"tutorials/AD-EdgeAI/#conversion-results","title":"Conversion results\u00b6","text":"At this point we should have a folder structure that looks like this:
models\n\u251c\u2500\u2500 ensemble_pipeline\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 1\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 config.pbtxt\n\u251c\u2500\u2500 postprocessor\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 1\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 model.py\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 config.pbtxt\n\u251c\u2500\u2500 preprocessor\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 1\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 model.py\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 config.pbtxt\n\u2514\u2500\u2500 tf_autoencoder_fp32\n \u251c\u2500\u2500 1\n \u2502\u00a0\u00a0 \u2514\u2500\u2500 model.savedmodel\n \u2502\u00a0\u00a0 \u251c\u2500\u2500 assets\n \u2502\u00a0\u00a0 \u251c\u2500\u2500 keras_metadata.pb\n \u2502\u00a0\u00a0 \u251c\u2500\u2500 saved_model.pb\n \u2502\u00a0\u00a0 \u2514\u2500\u2500 variables\n \u2502\u00a0\u00a0 \u251c\u2500\u2500 variables.data-00000-of-00001\n \u2502\u00a0\u00a0 \u2514\u2500\u2500 variables.index\n \u2514\u2500\u2500 config.pbtxt\n
"},{"location":"tutorials/AD-EdgeAI/#kura-deployment","title":"Kura Deployment\u00b6","text":"We can now move our pipeline to the target device for inference on the edge.
We want to perform anomaly detection in real time, directly within the edge device, using the same data we used to collect for our training.
"},{"location":"tutorials/AD-EdgeAI/#triton-component-configuration","title":"Triton component configuration\u00b6","text":"To do so we need to copy the models
folder on the target device. For this example we'll use the /home/pi/models
path.
We can now move to the Kura web UI and create a new Triton Server Container Service component instance. The complete documentation can be found here.
In this example we'll call it TritonContainerService
.
Then we'll need to configure it to run our models. Move to the TritonContainerService
configuration interface and set the following parameters:
nvcr.io/nvidia/tritonserver:22.07-tf2-python-py3
in this example./home/pi/models
preprocessor,postprocessor,tf_autoencoder_fp32,ensemble_pipeline
tensorflow,version=2
since Tensorflow 2 is the only available Tensorflow backend in the Triton container image we're using.You can leave everything else as default.
Once you press the \"Apply\" button Kura will create a new container from the Triton image we set and spin up the service with our models loaded.
pi@raspberrypi:~ $ docker ps\nCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES\n4deae2857b6f nvcr.io/nvidia/tritonserver:22.07-tf2-python-py3 \"tritonserver --mode\u2026\" 13 seconds ago Up 11 seconds 0.0.0.0:4000->8000/tcp, :::4000->8000/tcp, 0.0.0.0:4001->8001/tcp, :::4001->8001/tcp, 0.0.0.0:4002->8002/tcp, :::4002->8002/tcp tritonserver-kura\n
Note: if no container is created check that the \"Container Orchestration Service\" is enabled in the Kura UI. Full documentation for the service can be found here.
Note: if you see an error in the logs like \"Internal: Unable to initialize shared memory key 'triton_python_backend_shm_region_2' to requested size (67108864 bytes). If you are running Triton inside docker, use '--shm-size' flag to control the shared memory region size. Each Python backend model instance requires at least 64MBs of shared memory.\", you can update the default shared memory size allocated by the Docker daemon. Go to /etc/docker/daemon.json
, set \"default-shm-size\": \"200m\"
and restart the Docker daemon with: sudo systemctl restart docker
.
Finally we can move to the \"Wire Graph\" UI and create the AI component (in the Emitters/Receiver menu) for interfacing with the Triton instance we just created. We'll call it Triton
in this example.
We just need to change two parameter in the configuration:
TritonContainerService
we created at the step aboveThe resulting wire graph is the following:
And that's it! We should now see the anomaly detection results coming to Kapua in addition to the SenseHat data.
"},{"location":"tutorials/AD-EdgeAI/#complete-example","title":"Complete Example\u00b6","text":"A similar but more complete example of the feature presented in this notebook is available in the official Kura\u2122 repository containing all the code and the configuration needed to make it work.
Give it a try!
"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Home","text":""},{"location":"#welcome-to-the-eclipse-kuratm-documentation","title":"Welcome to the Eclipse Kura\u2122 Documentation","text":"The emergence of an Internet of Thing (IoT) service gateway model running modern software stacks, operating on the edge of an IoT deployment as an aggregator and controller, has opened up the possibility of enabling enterprise level technologies to IoT gateways.
Advanced software frameworks, which abstract and isolate the developer from the complexity of the hardware and the networking sub-systems, re-define the development and re-usability of integrated hardware and software solutions.
Eclipse Kura is an Eclipse IoT project that provides a platform for building IoT gateways. It is a smart application container that enables remote management of such gateways and provides a wide range of APIs for allowing you to write and deploy your own IoT application.
Kura runs on top of the Java Virtual Machine (JVM) and leverages OSGi, a dynamic component system for Java, to simplify the process of writing reusable software building blocks. Kura APIs offer easy access to the underlying hardware including serial ports, GPS, watchdog, USB, GPIOs, I2C, etc. It also offer OSGI bundle to simplify the management of network configurations, the communication with IoT servers, and the remote management of the gateway.
Kura components are designed as configurable OSGi Declarative Service exposing service API and raising events. While several Kura components are in pure Java, others are invoked through JNI and have a dependency on the Linux operating system.
Kura comes with the following services:
After developing your application and generating a deployment package that contains the bundles to be deployed (refer to the Development section for more information), you may install it on the gateway using the Packages option in the System area of the Kura Gateway Administration Console as shown below.
Upon a successful installation, the new component appears in the Services list (shown as the Heater example in these screen captures). Its configuration may be modified according to the defined parameters as shown the Heater display that follows.
"},{"location":"administration/application-management/#eclipse-kura-marketplace","title":"Eclipse Kura Marketplace","text":"Kura allows the installation and update of running applications via the Eclipse Kura Marketplace. The Packages page has, in the top part of the page a section dedicated to the Eclipse Kura Marketplace.
Dragging an application reference taken from the Eclipse Kura Marketplace to the specific area of the Kura Web Administrative Console will instruct Kura to download and install the corresponding package, as seen below:
Warning
If the installation from the Eclipse Marketplace fails, it can be for the lack of the correct certificates. In this case, import the certificate in the SSLKeystore from the Certificate List tab under the Security section. For more details about the procedure see here.
If the bundle is an official add-on for Eclipse Kura, the following certificate has to be imported:
-----BEGIN CERTIFICATE-----\nMIIHxzCCBq+gAwIBAgIQCCxCSNb4iszmNPNCflUcGTANBgkqhkiG9w0BAQsFADBP\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMSkwJwYDVQQDEyBE\naWdpQ2VydCBUTFMgUlNBIFNIQTI1NiAyMDIwIENBMTAeFw0yMzA5MTEwMDAwMDBa\nFw0yNDEwMTEyMzU5NTlaMG8xCzAJBgNVBAYTAkNBMRAwDgYDVQQIEwdPbnRhcmlv\nMQ8wDQYDVQQHEwZPdHRhd2ExJTAjBgNVBAoTHEVjbGlwc2Uub3JnIEZvdW5kYXRp\nb24sIEluYy4xFjAUBgNVBAMMDSouZWNsaXBzZS5vcmcwggIiMA0GCSqGSIb3DQEB\nAQUAA4ICDwAwggIKAoICAQC5hXH2cQoOQlXs5cQ5itZ1Dzct9R+bqr2HaF+imlgo\nxJ+Vw1ukfQPpSbmSO17A0hLgpSJyVgoPlpOKkg6LGTz8/2qB7DWHdQbg2p0IGQhr\ndm4oJN2qknnGNl/YYkjz2QJswr1M98raydmq0hqJi0M3q9JSO64O3wOMNduvNG+O\nrCBol7cbxLr7NNoFxZncZ9giP7QF0XYS6nA8dtIyXU3SARRSPn6y9OX1ttltveck\n41ocaU8ORiTF7i89t649XAbtsvxUWM+qVnvlMxpaXqbhnrXMQ/pV2yfdU/qiFQth\n+RqFgBYoX5roxvmjB14+2qlymn236N4KOGhvfr+Fp8C8Fv6N6wFyKZctXewQ6IsA\n3zDvJmF3QaCz6h88lg+IqbRjX5MOjhSkE7XDNKb+xAw5pYzkn9LP+QJLf0iYJw2D\nZ/X+InVPiZ5UdXyXWypN3q0W5vlz/TmWuVZv76/azZ3anoSPiKh+F3si1xZVEMZQ\nIkqsgUfq69M4KvHrdi4nGEOfdBHxjos9ul1AsJR57hrhIchsESthUK04e7d2LYOB\nhHAr0uJNdwFsFD2EBR25ogN83bZ8NaDrrdK2P6sV+hWWK+MY1qRuRub7/fYuR4AU\n82toms9p1usjuyMmuIGEpLwk7jZe6XITcbXQEXDA8JKSZrZ/mOA4yTfIGR/gXXB7\nwQIDAQABo4IDfTCCA3kwHwYDVR0jBBgwFoAUt2ui6qiqhIx56rTaD5iyxZV2ufQw\nHQYDVR0OBBYEFO8gL5LNWmSgCqbujR1qH0bUfrIrMCUGA1UdEQQeMByCDSouZWNs\naXBzZS5vcmeCC2VjbGlwc2Uub3JnMD4GA1UdIAQ3MDUwMwYGZ4EMAQICMCkwJwYI\nKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNVHQ8BAf8E\nBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMIGPBgNVHR8EgYcw\ngYQwQKA+oDyGOmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRMU1JT\nQVNIQTI1NjIwMjBDQTEtNC5jcmwwQKA+oDyGOmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0\nLmNvbS9EaWdpQ2VydFRMU1JTQVNIQTI1NjIwMjBDQTEtNC5jcmwwfwYIKwYBBQUH\nAQEEczBxMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wSQYI\nKwYBBQUHMAKGPWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRM\nU1JTQVNIQTI1NjIwMjBDQTEtMS5jcnQwDAYDVR0TAQH/BAIwADCCAX4GCisGAQQB\n1nkCBAIEggFuBIIBagFoAHYAdv+IPwq2+5VRwmHM9Ye6NLSkzbsp3GhCCp/mZ0xa\nOnQAAAGKhcgXYgAABAMARzBFAiEApQsk19PxbsLa452EPaPCXe7SAtpbm5RHnrwj\nyKAjWx0CICli5A3XAGwmg7IEy4lVA5YBt+mhvlegWkXrKt+oc/CoAHUASLDja9qm\nRzQP5WoC+p0w6xxSActW3SyB2bu/qznYhHMAAAGKhcgXWQAABAMARjBEAiAvx7lc\nMyKS6bbnsjbzYOLzJbcS2aAjCzQz4mFiuFA59AIgbt+rpE40/RO0JnFyLP9fsbUf\npUj16ZYinOLorqDk9r0AdwDatr9rP7W2Ip+bwrtca+hwkXFsu1GEhTS9pD0wSNf7\nqwAAAYqFyBc3AAAEAwBIMEYCIQDCrdQYGYA7BlsT5gXZmkutN15gDQDjlfJBxIRb\nZ0FAAgIhAIr0eNFvkpec6VJ5pPrNklFt78XP0NjEOJxjrCFTLKVdMA0GCSqGSIb3\nDQEBCwUAA4IBAQCvENXlAGP311/gV5rMD2frsK+hlcs/4wjRKUS+nwp3RLTRd3w4\ncZLHcsw9qCxeniuHsc/Wa6myr0kKdRc4V6movLq9vMdSjT9dDOZWtZgFaadB0+z2\nA/Jsq1/AFFWqWisF64627j/Wf7RwuasxM0dnkAl3m9Hli5xKPgjbovXiH/dCeMvS\nMTxD1p3ewIYITzV+1Q5FoFuGyIyuh1Kzo7A41xKPe+XfWHqt+hKL8MWkJ9ACD2b0\nZDlD2OaX7K+vI8aWprmwVdpp3deuUoHgBqa1PkHPRmP0bFbamBdB4H6goRX5+DEy\ncTW2rRm8jFiLm1kf0/iOL7/ddw0yZQAUMthU\n-----END CERTIFICATE-----\n
that has the following description:
Common Name: *.eclipse.org\nSubject Alternative Names: *.eclipse.org, eclipse.org\nOrganization: Eclipse.org Foundation, Inc.\nLocality: Ottawa\nState: Ontario\nCountry: CA\nValid From: September 10, 2023\nValid To: October 11, 2024\nIssuer: DigiCert TLS RSA SHA256 2020 CA1, DigiCert Inc Write review of DigiCert\nKey Size: 4096 bit\nSerial Number: 082c4248d6f88acce634f3427e551c19\n
If the bundle is not an official one and it is not hosted by Eclipse, retrieve the certificate with this command:
openssl s_client -showcerts -connect <download_link>:443\n
and import it in the SSLKeystore.
"},{"location":"administration/application-management/#package-signature","title":"Package Signature","text":"Once the selected application deployment package (dp) file is installed, it will be listed in the Packages page and detailed with the name of the deployment package, the version and the signature status. The value of the signature field can be true if all the bundles contained in the deployment package are digitally signed, or false if at least one of the bundles is not signed.
"},{"location":"administration/directory-layout/","title":"Directory Layout","text":"
This section describes the default Kura directory layout that is created upon installation. The default installation directory is as follows:
/opt/eclipse\n
The kura sub-directory is a logical link on the actual Kura release directory:
kura -> /opt/eclipse/kura_3.0.0_raspberry-pi-2\nkura_3.0.0_raspberry-pi-2\n
"},{"location":"administration/directory-layout/#kura-file-structure","title":"Kura File Structure","text":"The idea behind the Kura file and folder structure is to separate user and framework configuration files, that is files that can be modified by the user to customize Kura behavior and files that are used by Kura to persist configurations. Moreover, some files are generated at runtime by Kura (i.e. database) and they are kept in specific folders.
The user
, console
, log4j
and packages
directories contain files that can be modified by the user (i.e. the configuration for the logging or custom Kura properties). The framework
folder keeps the configuration files used by Kura and that shouldn't be modified by the user. The data
directory is used to persist files that are generated by Kura. Finally, the plugins
folder contains all the jar files needed by Kura. All of the Kura files are located within /opt/eclipse/kura
folder using the structure shown in the following table:
bin
Scripts that start Kura. console
This folder contains files that are used to customise the Kura Web UI appearance. data
Data files generated by the Kura runtime. data/persistance
Embedded Database files. packages
Deployment package files that are not part of the standard Kura framework, but are installed at a later time. framework
Configuration data for Kura framework. The user shouldn't directly modify these files. log
Log file from the latest Kura installation. log4j
Logger framework configuration plugins
All of the libraries and Kura specific jar files needed for the framework execution. user
Configuration files generated by the user or by Kura at runtime. These files can be modified by the user to customise the Kura behavior. user/snapshots
XML snapshot files; up to 10 successive configurations including the original. user/security
Files used by Kura to configure security. .data
Backup files needed to restore factory configuration"},{"location":"administration/directory-layout/#log-files","title":"Log Files","text":"Kura regularly updates two log files in the /var/log directory:
/var/log/kura-console.log - stores the standard console output of the application. This log file contains the eventual errors that are thrown upon Kura startup.
/var/log/kura.log - stores all of the logging information from Kura bundles. The logger levels are defined in the log4j.xml configuration file as shown below:
/opt/eclpse/kura/user/log4j.xml\n
The default logger level in this file is set to INFO. This level may be modified for the whole application or for a specific package as shown in the following example:
<Loggers>\n <Logger name=\"org.eclipse\" level=\"info\" additivity=\"false\">\n <AppenderRef ref=\"RollingFile\"/>\n </Logger>\n\n <Logger name=\"org.eclipse.kura.net.admin\" level=\"debug\" additivity=\"false\">\n <AppenderRef ref=\"RollingFile\"/>\n </Logger>\n\n <Root level=\"info\">\n <AppenderRef ref=\"RollingFile\"/>\n </Root>\n</Loggers>\n
In this example, the logger level is set to DEBUG only for the net.admin bundle. Additionally, more specific, properties may be defined as required for your particular logging needs. The logger levels are hierarchical, so that those in a deeper level of the hierarchy will apply; otherwise, the more general logger level will override them.
Once the logger levels are modified as needed and the log4j.xml configuration file is saved, Kura automatically loads the new configuration. By default Kura checks the file every 30 seconds.
"},{"location":"administration/remote-management-kapua/","title":"Remote Management with Eclipse Kapua","text":""},{"location":"administration/remote-management-kapua/#built-in-services-management","title":"Built-in Services Management","text":"This section describes the remote management of devices running Kura via Eclipse Kapua Console. The Eclipse Kapua Web Console provides the administration tools used for the management of the built-in services exposed by Kura.
To remotely manage a device running Kura through the Eclipse Kapua Web Console, select the desired device from the Devices Table of the console and open the Configuration tab as shown in the screen capture below. Please refer to the Built-in Services section for a description of the available Services and their configuration parameters.
"},{"location":"administration/remote-management-kapua/#installation-of-a-new-application","title":"Installation of a New Application","text":"As described in Application Management, a new application embedded in a deployment package can be deployed and configured using Eclipse Kapua Console.
To do so, select a connected device and click on the Packages tab. Then, click on Install/Upgrade. The Install New Package window opens allowing the deployment package to be installed from an URL as shown in the screen capture below. Once installed, the new application parameters may be modified in the same way as the Built-in Services. Click on the Configuration tab to see the service that corresponds to your application.
"},{"location":"administration/remote-management-kapua/#snapshots","title":"Snapshots","text":"As described in Snapshot Management, the overall Kura configuration, including the new installed applications, is stored in a snapshot xml file. The Eclipse Kapua Console also provides options to Download, Upload and Apply, or Rollback snapshots as shown in the screen capture below.
"},{"location":"administration/remote-management-kapua/#remote-command-execution-from-eclipse-kapua-web-console","title":"Remote Command Execution from Eclipse Kapua Web Console","text":"The Eclipse Kapua Console provides the ability to run system commands directly on the device. Refer to Command Service for details on how to configure this service in Kura.
It is also possible to send a script to execute using the File option of the Command tab in Eclipse Kapua Console as shown in the screen capture below. This script must be compressed into a zip file with the eventual associated resource files. Once the file is selected, click Execute.
The zip file is sent embedded in an MQTT message on the device. The Command Service in the device stores the file in /tmp, unzips it, and tries to execute a shell script if one is present. Note that in this case, the Execute parameter cannot be empty; a simple command, such as \"ls -l /tmp\", may be entered.
"},{"location":"administration/snapshot-management/","title":"Snapshot Management","text":"The overall configuration of Kura is stored in an XML file called a snapshot. This file includes all of the parameters for every service running in Kura. The original configuration file is named snapshot_0.xml. This section describes how snapshots may be used.
Each time a configuration change is made to one of the Kura components, a new XML file is created using the naming convention snapshot_[time as a long integer].xml. The nine most recent snapshots are saved, as well as the original snapshot 0.
"},{"location":"administration/snapshot-management/#how-to-access-snapshots","title":"How to Access Snapshots","text":"To display snapshots using the Gateway Administration Console, select Settings from the System area, and then click on the Snapshots tab. The following three operations are available: Download, Upload and Apply, and Rollback.
"},{"location":"administration/snapshot-management/#how-to-use-snapshots","title":"How to Use Snapshots","text":""},{"location":"administration/snapshot-management/#download","title":"Download","text":"The Download option provides the ability to save a snapshot file onto your computer. This file may then be edited, uploaded back to the device, or transferred to another equivalent device.
Starting from Kura 5.1, the snapshot can be downloaded in two formats:
takeSnapshot
parameter specified by the CONF-V2 request is missing from the downloaded JSON file, if that parameter is not specified, a new snapshot will be created by default.Pressing the Download button will trigger a dialog that allows choosing the desired format.
"},{"location":"administration/snapshot-management/#upload-and-apply","title":"Upload and Apply","text":"The Upload and Apply option provides the ability to import an XML file from your computer and upload it onto the device. This function updates every service in Kura with the parameters defined in the XML file.
Warning
Carefully select the file to be uploaded. An incorrect file may crash Kura and make it unresponsive.
"},{"location":"administration/snapshot-management/#rollback","title":"Rollback","text":"The Rollback option provides the ability to restore the system to a previous configuration.
"},{"location":"administration/system-component-inventory/","title":"System Component Inventory","text":"The Framework has the capability to report locally and to the associated cloud platform the list of currently installed components and their associated properties.
This feature allows, locally and remotely, the system administrator to know which components are installed into the target device and the associated versions. The feature is particularly important for a system administrator because allows to identify vulnerable components and allows immediate actions in response.
From the local Kura Web UI, the list of system components is available in the System Packages tab of the Device section. Once selected, the user will get the list of all the system installed components.
The component's inventory list is available also via REST APIs and, with the same contract, from the cloud. The Mqtt contract defined for this component is available here
"},{"location":"cloud-api/app-dev-guide/","title":"Application developer guide","text":"This guide will provide information on how an application developer can leverage the new Generic Cloud Services APIs, in order to be able to properly use the CloudPublisher/CloudSubscriber API, publish a message, being notified of message delivery and of connection status changes.
The Kura ExamplePublisher will be used as a reference.
The application should bind itself to a CloudPublisher
or CloudSubscriber
instance, this can be done in different ways, such as using OSGi ServiceTracker
s or by leveraging the Declarative Service layer.
The recommended way to perform this operation is choosing the latter and allowing the user to customize the service references through component configuration.
If the component metatype and definition are structured as described below, the Kura Web UI will show a dedicated widget in component configuration that helps the user to pick compatible CloudPublisher
or CloudSubscriber
instances.
Write component definition
The first step involves declaring the Publisher or Subscriber references in component definition:
<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\"\n name=\"org.eclipse.kura.example.publisher.ExamplePublisher\"\n activate=\"activate\"\n deactivate=\"deactivate\"\n modified=\"updated\"\n enabled=\"true\"\n immediate=\"true\"\n configuration-policy=\"require\">\n <implementation class=\"org.eclipse.kura.example.publisher.ExamplePublisher\"/>\n\n <!-- If the component is configurable through the Kura ConfigurationService, it must expose a Service. -->\n <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.example.publisher.ExamplePublisher\"/>\n <service>\n <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n </service>\n\n <reference name=\"CloudPublisher\"\n policy=\"static\"\n bind=\"setCloudPublisher\"\n unbind=\"unsetCloudPublisher\"\n cardinality=\"0..1\"\n interface=\"org.eclipse.kura.cloudconnection.publisher.CloudPublisher\"/>\n <reference name=\"CloudSubscriber\"\n policy=\"static\"\n bind=\"setCloudSubscriber\"\n unbind=\"unsetCloudSubscriber\"\n cardinality=\"0..1\"\n interface=\"org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber\"/>\n </scr:component>\n
The snipped above shows the definition of Kura ExamplePublisher, this component is capable of sending and receiving messages, and therefore defines two references, the first to a CloudPublisher
and the second to a CloudSubscriber
.
In order to allow the user to customize the bindings at runtime, the target
attribute of the references should not be specified at this point in component definition, as it will be set by the Web UI.
Reference cardinality should be use the 0..1
or 0..n
form, as it is not guaranteed that the references will point to a valid service instance during all the lifetime of the application component. For example, references can not be bound if the application has not been configured by the user yet or if the target service is missing.
Create component metatype
Application metatype should declare an AD
for each Publisher/Subscriber reference declared in component definition:
<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n <OCD id=\"org.eclipse.kura.example.publisher.ExamplePublisher\"\n name=\"ExamplePublisher\"\n description=\"Example of a Configuring Kura Application.\">\n\n <!-- ... -->\n\n <AD id=\"CloudPublisher.target\"\n name=\"CloudPublisher Target Filter\"\n type=\"String\"\n cardinality=\"0\"\n required=\"true\"\n default=\"(kura.service.pid=changeme)\"\n description=\"Specifies, as an OSGi target filter, the pid of the Cloud Publisher used to publish messages to the cloud platform.\">\n </AD>\n\n <AD id=\"CloudSubscriber.target\"\n name=\"CloudSubscriber Target Filter\"\n type=\"String\"\n cardinality=\"0\"\n required=\"true\"\n default=\"(kura.service.pid=changeme)\"\n description=\"Specifies, as an OSGi target filter, the pid of the Cloud Subscriber used to receive messages from the cloud platform.\">\n </AD>\n\n <!-- ... -->\n\n </OCD>\n <Designate pid=\"org.eclipse.kura.example.publisher.ExamplePublisher\" factoryPid=\"org.eclipse.kura.example.publisher.ExamplePublisher\">\n <Object ocdref=\"org.eclipse.kura.example.publisher.ExamplePublisher\"/>\n </Designate>\n </MetaData>\n
It is important to respect the following rules for some of the AD
attributes:
id
This attribute must have the following form:
<reference name>.target\n
where <reference name>
should match the value of the name
attribute of the corresponding reference in component definition.
required
must be set to true
default
must not be empty and must be a valid OSGi filter.
The Web UI will renderer a dedicated widget for picking CloudPublisher
and CloudSubscriber
instances:
Write the bind/unbind methods in applicaiton code
The last step involves defining some bind...()
/unbind...()
methods with a name that matches the values of the bind
/unbind
attributes of the references in component definition.
public void setCloudPublisher(CloudPublisher cloudPublisher) {\n...\n}\n\npublic void unsetCloudPublisher(CloudPublisher cloudPublisher) {\n...\n}\n\npublic void setCloudSubscriber(CloudSubscriber cloudSubscriber) {\n...\n}\n\npublic void unsetCloudSubscriber(CloudSubscriber cloudSubscriber) {\n...\n}\n
As stated above, since reference cardinality is declared as 0..
, the application must be prepared to handle the cases where references are not satisfied, and therefore CloudPublisher
and CloudSubscriber
instances are not available.
Publish a message
If a CloudPublisher
instance is bound, the application can publish messages using its publish()
method:
if (nonNull(this.cloudPublisher)) {\n KuraMessage message = new KuraMessage(payload);\n String messageId = this.cloudPublisher.publish(message);\n }\n
Receiving messages using a CloudSubscriber
In order to receive messages from a CloudSubscriber
, the application must implement and attach a CloudSubscriberListener
to it.
This can be done for example during CloudSubscriber
binding:
public class ExamplePublisher implements CloudSubscriberListener, ... {\n\n ...\n\n public void setCloudSubscriber(CloudSubscriber cloudSubscriber) {\n this.cloudSubscriber = cloudSubscriber;\n this.cloudSubscriber.registerCloudSubscriberListener(ExamplePublisher.this);\n ...\n }\n\n public void unsetCloudSubscriber(CloudSubscriber cloudSubscriber) {\n this.cloudSubscriber.unregisterCloudSubscriberListener(ExamplePublisher.this);\n ...\n this.cloudSubscriber = null;\n }\n\n ...\n\n @Override\n public void onMessageArrived(KuraMessage message) {\n logReceivedMessage(message);\n }\n\n ...\n\n }\n
The CloudSubscriber will invoke the onMessageArrived()
method when new messages are received.
Receiving connection state notifications
If an application is interested in cloud connection status change events (connected, disconnected, etc), it can implement and attach a CloudConnectionListener
to a CloudPublisher
or CloudSubscriber
instance.
public class ExamplePublisher implements CloudConnectionListener, ... {\n\n ...\n\n public void setCloudPublisher(CloudPublisher cloudPublisher) {\n this.cloudPublisher = cloudPublisher;\n this.cloudPublisher.registerCloudConnectionListener(ExamplePublisher.this);\n ...\n }\n\n public void unsetCloudPublisher(CloudPublisher cloudPublisher) {\n this.cloudPublisher.unregisterCloudConnectionListener(ExamplePublisher.this);\n ...\n this.cloudPublisher = null;\n }\n\n public void setCloudSubscriber(CloudSubscriber cloudSubscriber) {\n this.cloudSubscriber = cloudSubscriber;\n ...\n this.cloudSubscriber.registerCloudConnectionListener(ExamplePublisher.this);\n }\n\n public void unsetCloudSubscriber(CloudSubscriber cloudSubscriber) {\n ...\n this.cloudSubscriber.unregisterCloudConnectionListener(ExamplePublisher.this);\n this.cloudSubscriber = null;\n }\n\n ...\n\n @Override\n public void onConnectionEstablished() {\n logger.info(\"Connection established\");\n }\n\n @Override\n public void onConnectionLost() {\n logger.warn(\"Connection lost!\");\n }\n\n @Override\n public void onDisconnected() {\n logger.warn(\"On disconnected\");\n }\n\n ...\n\n }\n
Receiving message delivery notifications
If an application is interested in message confirmation events and the underlying cloud connection supports it, it can implement and attach a CloudDeliveryListener
to a CloudPublisher
instance.
public class ExamplePublisher implements CloudDeliveryListener, ... {\n\n ...\n\n public void setCloudPublisher(CloudPublisher cloudPublisher) {\n this.cloudPublisher = cloudPublisher;\n ...\n this.cloudPublisher.registerCloudDeliveryListener(ExamplePublisher.this);\n }\n\n public void unsetCloudPublisher(CloudPublisher cloudPublisher) {\n ...\n this.cloudPublisher.registerCloudDeliveryListener(ExamplePublisher.this);\n this.cloudPublisher = null;\n }\n\n ...\n\n @Override\n public void onMessageConfirmed(String messageId) {\n logger.info(\"Confirmed message with id: {}\", messageId);\n }\n\n ...\n\n }\n
The CloudSubscriber will invoke the onMessageConfirmed()
method when a published message is confirmed.
In order to determine which message has been confirmed, the provided messageId
can be compared with the id returned by the publish()
call that published the message.
Please note that if the underlying cloud connection is not able to provide message confirmation for the published message, the id returned by publish()
will be null
.
Eclipse Kura provides by default a set of services used to connect to a cloud platform. The following sections describe the services and how to configure them.
The CloudService
API is deprecated since Kura 4.0. The functionalities provided by CloudService
are now provided by the CloudEndpoint
and CloudConnectionManager
service interfaces. See the section describing the Kura 4.0 cloud connection model for more details.
The DataService
and MqttDataTrasport
APIs are not deprecated in Kura 4.0.
The CloudService provides an easy-to-use API layer for the M2M application to communicate with a remote server. It operates as a decorator for the DataService, providing add-on features over the management of the transport layer.
In addition to simple publish/subscribe, the CloudService API simplifies the implementation of more complex interaction flows like request/response or remote resource management. The CloudService abstracts the developers from the complexity of the transport protocol and payload format used in the communication.
The CloudService allows a single connection to a remote server to be shared across more than one application in the gateway providing the necessary topic partitioning. Its functions include:
Adds application topic prefixes to allow for a single remote server connection to be shared across applications.
Defines a payload data model and provides default encoding/decoding serializers.
Publishes life-cycle messages when the device and applications start and stop.
To use this service, select the CloudServices option located in the System area and select the CloudService tab as shown in the screen capture below.
The CloudService provides the following configuration parameters:
device.display-name
- defines the device display name given by the system. (Required field.)device.custom-name
- defines the custom device display name if the device.display-name parameter is set to \"Custom\".topic.control-prefix
- defines the topic prefix for system messages.encode.gzip
- defines if the message payloads are sent compressed.republish.mqtt.birth.cert.on.gps.lock
- when set to true, forces a republish of the MQTT Birth Certificate when a GPS correct position lock is received. The device is then registered with its real coordinates. (Required field.)republish.mqtt.birth.cert.on.modem.detect
- when set to true, forces a republish of the MQTT Birth Certificate when the service receives a modem detection event. (Required field.)enable.default.subscriptions
- when set to true, the gateway will not be remotely manageable.payload.encoding
- Specify the message payload encoding. The possible options are Kura Protobuf and Simple JSON.The default CloudService implementations publishes the following lifecycle messages:
The MqttDataTransport service provides the ability to connect to a remote broker, publish messages, subscribe to topics, receive messages on the subscribed topics, and disconnect from the remote message broker. To use this service, select the MqttDataTransport option located in the System area and select the CloudService tab as shown in the screen capture below.
The MqttDataTransport service provides the following configuration parameters:
broker-url
- defines the URL of the MQTT broker to connect to. (Required field.)topic.context.account-name
- defines the name of the account to which the device belongs.username
and password - define the username and password that have been assigned to the device by the account administrator (generally username is account-name_broker). (Required field.)client-id
- defines the identifier of the MQTT client representing the device when connecting to the MQTT broker. If left empty, it is automatically determined by the client software as the MAC address of the main network interface (in general numbers and uppercase letters without ':'). This identifier has to be unique within your account.keep-alive
- defines the \"keep alive\" interval measured in seconds. It specifies the maximum amount of time that should pass without communication between the client and the server. The client will ensure that at least one message travels across the network within each keep alive period. In the absence of a data-related message during this time period, the client will send a very small MQTT \"ping\" message that the server will acknowledge. The keep alive interval enables the client to detect when the server is no longer available without having to wait for the long TCP/IP timeout. (Required field.)timeout
- sets the timeout used for all interactions with the MQTT broker. (Required field.)clean-session
- controls the behavior of both the client and the server at the time of connect and disconnect. When this parameter is set to true, the state information is discarded at connect and disconnect; when set to false, the state information is maintained. (Required field.)lwt
parameters - define the MQTT \"Last Will and Testament\" (LWT) settings for the client. In the event that the client unexpectedly loses its connection to the server, the server publishes the LWT message (lwt.payload) to the LWT topic on behalf of the client. This allows other clients (subscribed to the LWT topic) to be made aware that the client has disconnected. LWT parameters that may be configured include:lwt.topic
lwt.payload
lwt.qos
lwt.retain
in-flight.persistence
- defines the storage type where in-flight messages are persisted across reconnections. They may be stored in memory, or in a file on the disk. (Required field.)protocol-version
- defines the MQTT Protocol version to be used. This value may be 3.1 or 3.1.1.ssl
parameters - defines the SSL configuration. SSL parameters that may be configured include:ssl.hostname.verification
ssl.default.cipherSuites
ssl.certificate.alias
This guide will provide information on how a cloud connection developer can leverage the new Generic Cloud Services APIs.
As reference, this guide will use the Eclipse IoT WG namespace implementation bundle available here
"},{"location":"cloud-api/cloud-conn-dev-guide/#implement-cloudendpoint-and-cloudconnectionmanager","title":"Implement CloudEndpoint and CloudConnectionManager","text":"In order to leverage the new APIs, and be managed by the Kura Web UI, the Cloud Connection implementation bundle must implement CloudEndpont and, if log-lived connections are supported, the CloudConnectionManager interface must be implemented as well.
The ending class should be something as follows:
public class CloudConnectionManagerImpl\n implements CloudConnectionManager, CloudEndpoint, ... {\n\n @Override\n public boolean isConnected() {\n ...\n }\n\n @Override\n public void connect() throws KuraConnectException {\n ...\n }\n\n @Override\n public void disconnect() {\n ...\n }\n\n @Override\n public Map<String, String> getInfo() {\n ...\n }\n\n @Override\n public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n ...\n }\n\n @Override\n public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n ...\n }\n}\n
A corresponding component definition should be provided in the OSGI-INF folder exposing the implementation of CloudEndpoint and CloudConnectionManager interfaces.
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" enabled=\"true\" immediate=\"true\" modified=\"updated\" name=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager\">\n <implementation class=\"org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud.CloudConnectionManagerImpl\"/>\n <service>\n <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n <provide interface=\"org.eclipse.kura.cloudconnection.CloudConnectionManager\"/>\n <provide interface=\"org.eclipse.kura.cloudconnection.CloudEndpoint\"/>\n <!-- ... -->\n </service>\n\n <!-- ... -->\n\n <property name=\"kura.ui.service.hide\" type=\"Boolean\" value=\"true\"/>\n <property name=\"kura.ui.factory.hide\" type=\"String\" value=\"true\"/>\n</scr:component>\n
In order to be fully compliant with the Web UI requirements, the CloudConnection component definition should provide two properties kura.ui.service.hide
and kura.ui.factory.hide
to hide the component from the left side part of the UI dedicated to display the services list.
The CloudConnectionFactory is responsible to manage the cloud connection instance lifecycle by creating the CloudEndpoint instance and all the required services needed to publish or receive messages from the cloud platform.
As a reference, please have a look at the CloudConnectionFactory defined for the Eclipse IoT WG namespace implementation.
In particular, the getFactoryPid()
method returns the PID of the CloudEndpoint factory. The createConfiguration()
method receives a PID that will be used for the instantiation of the CloudEndpoint and for all the related services required to communicate with the cloud platform. In the example above, the factory creates the CloudEnpoint, and a DataService and MqttDataTransport instances internally needed to communicate with a remote cloud platform. As can be seen here, the CloudEndpoint instance configuration is enriched with the reference to the CloudConnectionFactory that generated it. This step is required by the Web UI in order to properly relate the instances with the corresponding factories.
The deleteConfiguration()
method deletes from the framework the CloudEndpoint instance identified by the PID passed as argument and all the related services. In the Eclipse IOT WG example, it not only deletes the CloudEndpoint instance but also the corresponding DataService and MqttDataTransport instances.
The getStackComponentsPids()
method return a List of String that represent the kura.service.pid of the configurable components that are part of a Cloud Connection instance. This method is used by the Web UI to get the list of configurable components that need to be displayed to the end user.
The getManagedCloudConnectionPids()
method will return the list of kura.service.pid of all the CloudEndpoints managed by the factory.
The factory component definition should be defined as follows:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" name=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.DefaultCloudConnectionFactory\">\n <implementation class=\"org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud.factory.DefaultCloudConnectionFactory\"/>\n <reference bind=\"setConfigurationService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.configuration.ConfigurationService\" name=\"ConfigurationService\" policy=\"static\" unbind=\"unsetConfigurationService\"/>\n <service>\n <provide interface=\"org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory\"/>\n </service>\n <property name=\"osgi.command.scope\" type=\"String\" value=\"kura.cloud\"/>\n <property name=\"osgi.command.function\" type=\"String\">\n createConfiguration\n </property>\n <property name=\"kura.ui.csf.pid.default\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager\"/>\n <property name=\"kura.ui.csf.pid.regex\" type=\"String\" value=\"^org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager(\\-[a-zA-Z0-9]+)?$\"/>\n <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.DefaultCloudConnectionFactory\"/>\n</scr:component>\n
In particular, it should expose in the service
section the fact that the factory implements org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory
<service>\n <provide interface=\"org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory\"/>\n </service>\n
Important properties that need to be specified to have a better Web UI experience are the following:
<property name=\"kura.ui.csf.pid.default\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager\"/>\n<property name=\"kura.ui.csf.pid.regex\" type=\"String\" value=\"^org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager(\\-[a-zA-Z0-9]+)?$\"/>\n
those allow to specify the form of the expected PID that the end user should provide when creating a new cloud connection."},{"location":"cloud-api/cloud-conn-dev-guide/#provide-a-cloudpublisher-implementation","title":"Provide a CloudPublisher implementation","text":"To provide a CloudPublisher implementation, other than implementing CloudPublisher API in a java class, the developer must provide a component definition in the OSGI-INF folder that should be like the following:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" enabled=\"true\" immediate=\"true\" modified=\"updated\" name=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher\">\n <implementation class=\"org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud.publisher.CloudPublisherImpl\"/>\n <service>\n <provide interface=\"org.eclipse.kura.cloudconnection.publisher.CloudPublisher\"/>\n <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n </service>\n <property name=\"cloud.connection.factory.pid\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager\"/>\n <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher\"/>\n <property name=\"kura.ui.service.hide\" type=\"Boolean\" value=\"true\"/>\n <property name=\"kura.ui.factory.hide\" type=\"String\" value=\"true\"/>\n <property name=\"kura.ui.csf.pid.default\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher\"/>\n <property name=\"kura.ui.csf.pid.regex\" type=\"String\" value=\"^org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher(\\-[a-zA-Z0-9]+)?$\"/>\n</scr:component>\n
As can be seen in the previous snippet, the Publisher exposes itself in the framework as a ConfigurableComponent
and as a CloudPublisher
.
The component definition must contain the following well-known properties:
cloud.connection.factory.pid
: this property must be set to the kura.service.pid of the factory that created the cloud connection which the publisher belongs. It is used by the Web UI to enforce that the correct cloud publisher implementation is used in a specific cloud endpoint. kura.ui.service.hide
: as specified before for the Cloud Endpointkura.ui.factory.hide
: as specified before for the Cloud Endpointkura.ui.csf.pid.default
: as specified before for the Cloud Factory. It is an optional property.kura.ui.csf.pid.regex
: as specified before for the Cloud Factory. It is an optional property.The relation between the CloudPublisher instance and the CloudEndpoint is defined by a configuration property set by the Web UI at CloudPublisher creation.
"},{"location":"cloud-api/cloud-conn-dev-guide/#provide-a-cloudsubscriber-implementation","title":"Provide a CloudSubscriber implementation","text":"The CloudSubscriber implementation and component definition is similar to the one described for the CloudPublisher.
"},{"location":"cloud-api/cloud-conn-dev-guide/#implement-requesthandler-support","title":"Implement RequestHandler support","text":"In order to support Command and Control, the cloud connection bundle should provide a service that registers itself as RequestHandlerRegistry. In this way all the RequestHandler instances could be able to discover the different Registry and subscribe for command and control messages received from the cloud platform. As an example, for the Eclipse IoT WG bundle, the CloudEndpoint registers itself also as RequestHandlerRegistry.
"},{"location":"cloud-api/overview/","title":"Overview","text":"This section describes the new cloud related concepts and APIs introduced in Kura 4.0.
"},{"location":"cloud-api/overview/#motivations","title":"Motivations","text":"Before Kura 4.0, Cloud APIs were quite tied to Kapua messaging conventions and to the MQTT protocol. Defining custom stacks that support other cloud platforms was possible, but the resulting implementations were affected by the following limitations:
The legacy APIs assume that the underlying messaging protocol is MQTT. This assumption spans across all API layers, from the low level MQTTDataTrasport
to the high level CloudClient
. This makes quite difficult to implement cloud stacks that use other protocols like AMQP or HTTP.
The CloudClient
API, which was the recommended way for applications to interface with a cloud stack, enforce the following MQTT topic structure:
#account-name/#device-id/#app-id/<app-topic>\n
This topic hierarchy, which is Kapua related, might be too restrictive or too loose for other cloud platforms, for example: accont-name
and device-id
parameters in the topic. Moreover, telemetry, alert and event message topics must start respectively the t/
, a/
and e/
prefixes. Adhering to this specification is not possible for a cloud stack that implements the legacy APIs.CloudClient
would be quite restrictive in this case. A way for overcoming this limitation for an application might be using the DataService layer directly, adversely affecting portability.CloudClient
in this case makes difficult for the cloud stack to enforce that the messages are published on the correct topics. Moreover, the cloud stack in this case must also convert from KuraPayload
to CSV, this can be currently achieved only by introducing rigid conversion rules, that might not be enough to support all message formats.Applications that use the current APIs are not portable across cloud platforms. For example if an appliaction intends to publish on Cumulocity or AWS, it should be probably aware of the underlying cloud platform.
The main interfaces of the new set of APIs and their interactions are depicted in the diagram below:
As shown in the above diagram new APIs introduce the concept of Cloud Connection, a set of related services that allow to manage the communication to/from a remote cloud platform.
The services that compose a Cloud Connection can implement the following cloud-specific interfaces:
CloudEndpoint (required): Each Cloud Connection is identified by a single instance of CloudEndpoint that implements low level specificities for the communication with the remote cloud platform.
CloudConnectionManager (optional): Exposes methods that allow to manage long-lived connections. The implementor of CloudEndpoint can implement this interface as well if the cloud platform support long-lived connections (for example by using the MQTT protocol).
RequestHandlerRegistry (optional): Manages the command and control functionalities if supported by the cloud platform.
CloudPublisher (optional): Allows applications to publish messages to the cloud platform in a portable way.
CloudSubscriber (optional): Allows applications to receive messages from the cloud platform in a portable way.
CloudConnectionFactory (required): Manages the lifecycle of Cloud Connections.
A Cloud Connection can also include services that do not provide any of the interfaces above but compose the internal implementation.
"},{"location":"cloud-api/overview/#cloudendpoint","title":"CloudEndpoint","text":"Every Cloud Connection must contain a single CloudEndpoint
instance. The kura.service.pid
of the CloudEndpoint
identifies the whole Cloud Connection.
The CloudEndpoint
provides some low level methods that can be used to interact with the remote cloud platform.
For example the interface provides the publish()
and subscribe()
methods that allow to publish or receive messages from the cloud platform in form of KuraMessage
s. Those methods are designed for internal use and are not intended to be used by end-user applications.
The format of the KuraMessage
provided to/received from a CloudEndpoint
is implementation specific: the CloudEndpoint
expects some properties to be set in the KuraMessage to be able to correctly publish a message (e.g. MQTT topic). These properties are specified by the particular CloudEndpoint
, and should be documented by the implementor.
The recommended way for applications to publish and receive messages involves using the Publisher and Subscriber APIs described below. If an application directly uses the methods above, it will lose portability and will be tied to the specific Cloud Connection implementation.
"},{"location":"cloud-api/overview/#cloudconnectionmanager","title":"CloudConnectionManager","text":"If the messaging protocol implemented by a Cloud Connection supports long-lived connection, then its CloudEndpoint
can also implement and provide the CloudConnectionManager
interface.
This interface exposes some methods that can be used to manage the connection like connect()
, disconnect()
and isConnected()
; it also supports monitoring connection state using the CloudConnectionListener
interface.
The limitations of the current model described above are addressed by the introduction of the CloudPublisher
and CloudSubscriber
APIs, that replace the CloudClient
as the recommended interface between applications and cloud stacks. CloudPublisher
and CloudSubscriber
are service interfaces defined as follows:
public interface CloudPublisher {\n\n public String publish(KuraMessage message) throws KuraException;\n\n public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener);\n\n public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener);\n\n public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener);\n\n public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener);\n\n}\n
public interface CloudSubscriber {\n\n public void registerCloudSubscriberListener(CloudSubscriberListener listener);\n\n public void unregisterCloudSubscriberListener(CloudSubscriberListener listener);\n\n public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener);\n\n public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener);\n\n}\n
"},{"location":"cloud-api/overview/#cloudpublisher","title":"CloudPublisher","text":"The CloudPublisher
interface should be used by applications for publishing messages using the single publish()
method. This method accepts a KuraMessage
which is basically a KuraPayload
that can be enriched with metadata.
The main difference with the CloudClient
APIs is that the publish()
method does not require the application to specify any information related to message destinations. This allows to write portable applications that are unaware of the low level details of the destination cloud platform, such as the message format and the transport protocol.
An application designed to receive messages from the cloud must now attach a listener (CloudSubscriberListener
) to a CloudSubscriber
instance.
In this case, the message source cannot be specified by the application but is defined by the subscriber instance, in the same way as the CloudPublisher
defines destination for published messages.
The low level details necessary for message delivery and reception (e.g. the MQTT topic and the conversion between KuraMessage
and the message format used on the wire) are managed by the publisher/subscriber, typically these details are stored in the service configuration.
While in the previous model an application was responsible to actively obtain a CloudClient
instance from a CloudService
, now the relation between the application and a CloudPublisher or CloudSubscriber instance is represented as an OSGi service reference. Applications should allow the user to modify this reference in configuration, making it easy to switch between different cloud publisher/subscriber instances and different cloud platforms.
Publisher/subscriber instances are now typically instantiated and configured by the end user using the Web UI.
Publisher/subscriber instances are related to a CloudEnpoint
instance using an OSGi service reference encoded in well known configuration property specified in the APIs (CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME
). This allows the user to create those instances in a dedicated section of the Web UI.
Another field in which the current Kura cloud related APIs can be generalized is related to command and control. In the previous model this aspect was covered by the Cloudlet
APIs that are now replaced by RequestHandler
APIs
Legacy Cloudlet
implementations are defined by extending a base class, Cloudlet
, which takes care of handling the invocation of the doGet()
, doPut()
, doPost()
... methods, and of correlating request and response messages. Messages were sent and received through a CloudClient
.
More explicitly, Cloudlet
only works with control topics whose structure is
$EDC/<account-name>/<device-id>/<app-id>/<method>/<resource-path>\n
and also expects the identifier of the sender and the correlation identifier in the KuraPayload
. In the previous model, there is no way for a cloud stack implementor to customize the aspects above, which are hardcoded in the Cloudlet
base class.
The new model delegates these aspects to some component of the cloud stack, and requires applications that want to support command and control to register themselves as RequestHandler
to a RequestHandlerRegistry
instance.
In order to ease porting old applications to the new model, some of the concepts of the old Cloudlet APIs are still present, this can be seen by looking at the RequestHandler
interface definition:
public interface RequestHandler {\n\n public KuraMessage doGet(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException;\n\n public KuraMessage doPut(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException;\n\n public KuraMessage doPost(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException;\n\n public KuraMessage doDel(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException;\n\n public KuraMessage doExec(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException;\n}\n
A RequestHandler
invocation involves the following parameters:
Request parameters:
RequestHandler
method to be calledKuraPayload
wrapped inside the KuraMessage
.List<String>
of positional parameters available under the well known args
key in the provided KuraMessage
properties.Response parameters:
KuraPayload
wrapped inside the returned KuraMessage
.RequestHandler
methods returns without throwing exceptions.RequestHandler
methods throws a KuraException
with KuraErrorCode
== BAD_REQUESTRequestHandler
methods throws a KuraException
with KuraErrorCode
== NOT_FOUNDRequestHandler
methods throws a KuraException
with other error codes.KuraException
thrown by the RequestHandler
methods, if any.KuraException
thrown by the RequestHandler
methods, if any.The parameters above are the same involved in current Cloudlet calls. The request id and requester client id parameters are no longer part of the API, because are related to the to the way Kapua correlates requests and response. In the new API, request and response identifiers are not specified and not forwarded to the Cloudlet, this allows the CloudletService implementation to adopt the platform specific conventions for message correlation.
The Cloudlet parameters must be present in the request and response messages encoded in some format. A user that intends to call a Kura Cloudlet, for example through platform-specific REST APIs must be aware of these parameters. The user must supply request parameters in request message and must be able to extract response data from received message. The actual encoding of these parameters inside the messages depends on the particular platform.
The fact that set of Cloudlet parameters are roughly the same involved in current Cloudlet calls allows existing Cloudlet based applications to continue to work without changes to the protocol.
"},{"location":"cloud-api/overview/#cloud-connection-lifecycle","title":"Cloud Connection lifecycle","text":"CloudEndpoint
instance lifecycle is managed by a CloudConnectionFactory
instance. A cloud connection implementor must register a CloudConnectionFactory
instance in the framework that is responsible of creating and destroying the CloudEndpoint
instances.
The CloudConnectionFactory
will be typically invoked by the Web UI, and is defined as follows:
public interface CloudConnectionFactory {\n\n public static final String KURA_CLOUD_CONNECTION_FACTORY_PID = \"kura.cloud.connection.factory.pid\";\n\n public String getFactoryPid();\n\n public void createConfiguration(String pid) throws KuraException;\n\n public List<String> getStackComponentsPids(String pid) throws KuraException;\n\n public void deleteConfiguration(String pid) throws KuraException;\n\n public Set<String> getManagedCloudConnectionPids() throws KuraException;\n\n}\n
The createConfiguration()
and deleteConfiguration()
methods are responsible of creating/destroying a CloudEndpoint
instance, specified by the provided kura.service.pid
, and all the related services.
The getManagedCloudConnectionPids()
returns the set of kura.service.pid
managed by the factory.
The getStackComponentsPids(String pid)
returns the list of the kura.service.pid
s of the ConfigurableComponent
s that are associated with the CloudEndpoint
with the specified pid. The Web Ui will render the configuration of those components in separated tabs, in the dedicated CloudConnections section.
In order to ease the transition to the new model, legacy APIs like CloudService
and CloudClient
are still supported in Kura 4.0.0, even if deprecated.
The default Kapua oriented CloudService
implementation is still available and can be used by legacy applications without changes. The default CloudService
instance in Kura 4.0 also implements the new CloudEndpoint
and CloudConnectionManager
interfaces.
This guide will illustrate the steps required for configuring an application that uses the new Cloud Connection APIs to publish messages to the Kapua platform.
The involved steps are the following
Open the Cloud Connections section of the Web UI:
Create a new Cloud Connection
Click on the New Connection button
Enter a new unique identifier in the Cloud Connection Service PID field. The identifier must be a valid kura.service.pid
and, in case of a Kapua Cloud Connection, it must start with the org.eclipse.kura.cloud.CloudService-
prefix. A valid identifier can be org.eclipse.kura.cloud.CloudService-KAPUA
. As an alternative it is possible to reconfigure the existing org.eclipse.kura.cloud.CloudService
Cloud Connection.
Configure the MQTTDataTrasport
service.
Click on the MQTTDataTrasport-KAPUA
tab and fill the parameters required for establishing the MQTT connection:
Broker-url
Topic Context Account-Name
Username
Password
Configure the DataService-KAPUA
service.
In order to enable automatic connection, set the Connect Auto-on-startup
parameter to true
Select to the connection to be used from the list.
Click on the New Pub/Sub button.
Select the type of component to be created, from the Available Publisher/Subscriber factories drop down list, in order to create a Publisher select the org.eclipse.kura.cloud.publisher.CloudPublisher
entry.
Enter an unique kura.service.pid identifier in the New Publisher/Subscriber PID field.
Click Apply, you should see the publisher configuration
Select and configure the newly created publisher instance, and then click Apply
Select the application instance configuration
Find the configuration entry that represents a Publisher reference.
Click on the Select available targets link and select the desired Publisher instance to bind to.
Click on Apply
This section provides a guide on connecting an Eclipse Kura\u2122 device to the Amazon AWS IoT platform.
"},{"location":"cloud-platform/kura-aws-cloud/#prerequisites","title":"Prerequisites","text":"The first step involves the registration of the new device on AWS, this operation can be done using the AWS Web Console or with the AWS CLI command line tool, in this guide the Web based console will be used.
"},{"location":"cloud-platform/kura-aws-cloud/#1-access-the-aws-iot-management-console","title":"1. Access the AWS IoT management console.","text":"This can be done by logging in the AWS console and selecting IoT Core from the services list, in the Internet of Things section.
"},{"location":"cloud-platform/kura-aws-cloud/#2-create-a-default-policy-for-the-device","title":"2. Create a default policy for the device.","text":"This step involves creating a default policy for the new device, skip if an existing policy is already available.
Access the main screen of the console and select Secure -> Policies from the left side menu and then press the Create button, in the top right area of the screen.
Fill the form as follows and then press the Create button:
iot:Connect, iot:Publish, iot:Subscribe, iot:Receive, iot:UpdateThingShadow, iot:GetThingShadow, iot:DeleteThingShadow
*
Allow
This will create a policy that allows a device to connect to the platform, publish/subscribe on any topic and manage its thing shadow.
"},{"location":"cloud-platform/kura-aws-cloud/#3-register-a-new-device","title":"3. Register a new device.","text":"Devices on the AWS IoT platform are called things, in order to register a new thing select Manage -> Things from the left side menu and then press the Create button, in the top right section of the screen. Select Create a single thing.
Enter a name for the new device and then press the Next button, from now on kura-gateway
will be used as the device name.
The AWS IoT platform uses SSL mutual authentication, for this reason it is necessary to download a public/private key pair for the device and a server certificate. Click on Create certificate to quickly generate a new certificate for the new device.
Certificates can be managed later on by clicking on Secure -> Certificates, in the left part of the console.
"},{"location":"cloud-platform/kura-aws-cloud/#5-download-the-device-ssl-keys","title":"5. Download the device SSL keys.","text":"You should see a screen like the following:
Download the 3 files listed in the table and store them in a safe place, they will be needed later, also copy the link to the root CA for AWS IoT in order to be able to retrieve it later from the device.
Press the Activate button, and then on Attach a policy.
"},{"location":"cloud-platform/kura-aws-cloud/#6-assign-the-default-policy-to-the-device","title":"6. Assign the default policy to the device.","text":"Select the desired policy and then click on Register thing.
A policy can also be attached to a certificate later on perforiming the following steps:
Enter the device configuration section, by clicking on Manage -> Things and then clicking on the newly created device. Click on Security on the left panel and then click on the certificate entry (it is identified by an hex code), select Policies in the left menu, you should see this screen:
Click on Actions in the top left section of the page and then click on Attach policy, select the default policy previously created and then press the Attach button.
"},{"location":"cloud-platform/kura-aws-cloud/#device-configuration","title":"Device configuration","text":"The following steps should be performed on the device, this guide is based on Kura 3.1.0 version and has been tested on a Raspberry PI 3.
"},{"location":"cloud-platform/kura-aws-cloud/#7-create-a-java-keystore-on-the-device","title":"7. Create a Java keystore on the device.","text":"The first step for using the device keys obtained at the previous step is to create a new Java keystore containing the Root Certificate used by the Amazon IoT platform, this can be done executing the following commands on the device:
sudo mkdir /opt/eclipse/kura/security\n
cd /opt/eclipse/kura/security\n
curl https://www.amazontrust.com/repository/AmazonRootCA1.pem > /tmp/root-CA.pem\n
sudo keytool -import -trustcacerts -alias aws -file /tmp/root-CA.pem -keystore cacerts.ks -storepass changeit\n
If the last command reports that the certificate already exist in the system-wide store type yes
to proceed. The code above will generate a new keystore with changeit
as password, change it if needed.
Open the Kura Web Console and enter select the Settings entry in the left side menu and then click on SSL Configuration, you should see this screen:
Change the Keystore path parameter to /opt/eclipse/kura/security/cacerts.ks
if needed.
Change the settings in the form to match the screen above, set Default protocol to TLSv1.2, enter changeit
as Keystore Password (or the password defined at step 7).
Warning
Steps from 8.2 to 8.6 will not work on Kura 3.2.0 due to a known issue. On this version, private key and device certificate need to be manually added to the keystore using the command line. If you are running Kura 3.2.0, proceed with step 8.7.
Open the Kura Web Console and enter select the Settings entry in the left side menu and then click on Device SSL Certificate, you should see this screen:
Enter aws-ssl
in the Storage Alias field.
The private key needs to be converted to the PKCS8 format, this step can be performed executing the following command on a Linux or OSX based machine:
openssl pkcs8 -topk8 -inform PEM -outform PEM -in xxxxxxxxxx-private.pem.key -out outKey.pem -nocrypt\n
where xxxxxxxxxx-private.pem.key
is the file containing the private key downloaded at step 4.
Paste the contents of the obtained outKey.pem
in the \"Private Key\" field.
Paste the contents of xxxxxxxxxx-certificate.pem.crt
in the Certificate field.
You should see a screen like this
Click the Apply button to confirm.
Kura 3.2.0 only - manually import device certificate and private key into keystore.
On the host machine, open a terminal window in the folder containing the files downloaded at step 5 and execute the following command:
openssl pkcs12 -export -in xxxxxxxxxx-certificate.pem.crt -inkey xxxxxxxxxx-private.pem.key -name aws-ssl -out aws-ssl.p12\n
where xxxxxxxxxx-certificate.pem.crt
is the original certificate downloaded from AWS and xxxxxxxxxx-private.pem.key
is the private key.
The command will ask for a password, define a new password.
Copy the obtained aws-ssl.p12
file to the device into the /tmp
folder using scp:
scp ./aws-ssl.p12 pi@<device-address>:/tmp\n
Replacing <device-address>
with the hostname or ip address of the device.
Open a ssh connection to the device and enter the following command:
sudo keytool -importkeystore -deststorepass changeit -destkeystore /opt/eclipse/kura/security/cacerts.ks -srckeystore /tmp/aws-ssl.p12 -srcstoretype PKCS12\n
The command will ask for a password, enter the password defined when creating the aws-ssl.p12
file.
Restart Kura to reload the keystore.
Click on Cloud Connections in the left panel, and setup a new cloud connection
Click on the New Connection button at the top of the page and set the following parameters in the dialog:
org.eclipse.kura.cloud.CloudService
org.eclipse.kura.cloud.CloudService-AWS
Press the Create button to confirm and then select the newly created CloudService instance from the list.
Set the broker URL in the MqttDataTransport-AWS tab, it can be obtained from the AWS IoT Web Console clicking on the Settings entry in the bottom left section of the page, the URL will look like the following:
a1rm1xxxxxxxxx.iot.us-east-1.amazonaws.com\n
The mqtts protocol must be used, the value for the broker-url field derived from the URL above is the following:
mqtts://a1rm1xxxxxxxxx.iot.us-east-1.amazonaws.com:8883/\n
Clear the value of the username and password fields.
Set a value for the topic.context.account-name and client-id.
Assign an arbitrary account name to topic.context.account-name (for example aws-test
), this will be used by the CloudClient instances for building the topic structure.
Enter the thing name in the client-id field (in this example kura-gateway
).
In order for the previously added keys to be used for the SSL connection with the broker enter the Storage Alias defined in step 8.2 (e.g aws-ssl
) as value for the ssl.certificate.alias field.
The setting lwt.topic under MqttDataTransport-AWS needs to be updated as well by entering a value not containing the $ character. This is required because of the fact that AWS IoT does not support topic names starting with $ (except for the $aws/ hierarchy).
Press the Apply button in the top left section to commit the changes to the MqttDataTransport-AWS.
Enter a name without the $ character for the topic.control-prefix setting in the CloudService-AWS tab, for example aws-control
.
The Kura CloudService uses some well-known topics to allow remote device management and to report device state information, this features are not supported by default by AWS IoT, the following settings can be applied in the CloudService-AWS tab in order to avoid sending unnecessary messages:
false
false
false
Click the Apply button to save the changes.
Make sure the AWS CloudService instance is selected from the list in the top section of the page and click on the Connect button, if the connection to AWS IoT platform succeeds the Status of the instance will be reported as Connected.
"},{"location":"cloud-platform/kura-azure/","title":"Azure IoT Hub\u2122 platform","text":"Starting from release 3.0, Eclipse Kura can connect to the Azure IoT Hub using the MQTT protocol. When doing so, Kura applications can send device-to-cloud messages. More information on the Azure IoT Hub and its support for the MQTT protocol can be found here. This document outlines how to configure and connect a Kura application to the Azure IoT Hub.
"},{"location":"cloud-platform/kura-azure/#get-azure-iot-hub-information","title":"Get Azure IoT Hub information","text":"In order to properly configure Kura to connect to IoT Hub, some information are needed. You will need the hostname of the Azure IoT Hub, referred below as {iothubhostname}
, the Id and the SAS Token of the device, referred as {device_id}
and {device_SAS_token}
. The hostname is listed on the \"Overview\" tab on the IoT Hub main page, while the device ID is shown on the \"Device Explorer\" tab. Finally, the SAS token can be generated using the iothub-explorer application that can be found here. To install the application, type on a shell:
npm install -g iothub-explorer\n
Then start a new session on your IoT Hub instance (it will expire in 1 hour):
iothub-explorer login \"{your-connection-string}\"\n
where {your-connection-string}
is the connection string of your IoT Hub instance. It can be found on the \"Shared access policies\" tab under \"Settings\". Select the \"iothubowner\" policy and a tab will appear with the \"Connection string\u2014primary key\" option. Then list your devices:
iothub-explorer list\n
and get the SAS token for the {device-name}
device:
iothub-explorer sas-token {device-name}\n
Be aware that the SAS token will expire in 1 hour by default, but using \"-d\" option it is possible to set a custom expiration time.
"},{"location":"cloud-platform/kura-azure/#ssl-certificates","title":"SSL certificates","text":"In order to connect to your IoT Hub instance, Kura should trust the remote broker through a SSL certificate. The simpler way to get the IotHub certificate is to run the following command on a shell:
openssl s_client -showcerts -tls1 -connect {iothubhostname}:8883\n
The result is the SSL certificate chain. Copy all the certificates in the format:
-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n
and paste them in to the \"Server SSL Certificate\" tab under \"Settings\" in Kura. Then click the Apply button and restart Kura to update the keystore.
"},{"location":"cloud-platform/kura-azure/#configuring-a-kura-cloud-stack-for-azure-iot-hub","title":"Configuring a Kura Cloud Stack for Azure IoT Hub","text":"The Kura Gateway Administrative Console exposes all services necessary to configure a connection to the Azure IoT Hub. You can follow the steps outlined below to configure the connection to the Azure IoT Hub.
The first step is to create a new Kura Cloud stack. From the Kura Gateway Administrative Console:
org.eclipse.kura.cloud.CloudService
as the Cloud Connection Factory PIDorg.eclipse.kura.cloud.CloudService-Azure
Now review and update the configuration of each Kura Cloud stack component as outline below.
Modify the service configuration parameters as follows:
broker-url - defines the URL of the Azure IoT MQTT broker. The URL value should be set as mqtts://{iothubhostname}:8883/
Note
An SSL connection (mqtts on port 8883) is required to connect to Azure IoT Hub\u2122.
topic.context.account-name - insert devices
as the MQTT topic prefix for the device-to-cloud and cloud-to-device messages
{iothubhostname}/{device_id}
as username for the MQTT connectionpassword - insert {device_SAS_token}
as password for the MQTT connection
Note
The format of the SAS Token is like:
SharedAccessSignature sig={signature-string}&se={expiry}&sr={URL-encoded-resourceURI}\n
client-id - insert {device_id}
as Client ID for the MQTT connection
true
#account-name/#client-id/messages/events/LWT
You can keep the default values of the remaining parameters, so save your changes by clicking the Apply button. A screen capture of the MqttDataTransport configuration is shown below.
"},{"location":"cloud-platform/kura-azure/#dataservice","title":"DataService","text":"The majority of default settings in the DataService can be left unchanged. A screen capture of the DataService configuration is shown below.
In order for Kura to connect to Azure IoT Hub on startup, the connect.auto-on-startup option must be set to true. If this value is changed from false to true, Kura will immediately begin the connection process. It is recommended that the CloudService and MqttDataTransport are configured before setting the connect.auto-on-startup option to true.
Note
Changing the value of connect.auto-on-startup from true to false will not disconnect the client from the broker. This setting simply implies that Kura will not automatically connect on the next start of Kura.
"},{"location":"cloud-platform/kura-azure/#cloudservice","title":"CloudService","text":"The default settings for the CloudService should be modified as follow to allow a connection to Azure IoT Hub .
devices
as the MQTT topic prefix for the device-to-cloud and cloud-to-device messagesfalse
to avoid compression of the message payloadsfalse
to avoid sending additional messages on GPS position lockfalse
to avoid sending additional messages on cellular modem updatefalse
to avoid subscriptions on Kura control topics for cloud-to-deviceSimple JSON
The screen capture shown below displays the default settings for the CloudService.
"},{"location":"cloud-platform/kura-azure/#how-to-connect-and-disconnect-from-the-cloud-platform","title":"How to connect and disconnect from the cloud platform","text":"The status panel can be used to manually connect or disconnect the client while Kura is running. The main button toolbar has a connect and disconnect button that may be used to control connectivity.
Note
Connecting or disconnecting the client via the status panel has no impact on Kura automatically connecting at startup. This capability is only controlled via the connect.auto-on-startup DataService setting.
"},{"location":"cloud-platform/kura-azure/#kura-application-connecting-to-azure-iot-hub","title":"Kura Application Connecting to Azure IoT Hub","text":"The Kura example publisher can be used to publish to the IoT Hub. The example configuration should be modified as follows.
org.eclipse.kura.cloud.CloudService-Azure
in this tutorialmessages
as application idevents/
as publish topicThis configuration allows the publication on the default messages/events
endpoint on the IoT Hub\u2122.
Everyware Cloud provides an easy mechanism for connecting cloud-ready devices to IT systems and/or applications; therefore, connecting to Everyware Cloud is an important step in creating and maintaining a complete M2M application. Information on Everyware Cloud and its features can be found here. This document outlines how to connect to Everyware Cloud using the Kura Gateway Administrative Console.
"},{"location":"cloud-platform/kura-ec-cloud/#using-the-kura-gateway-administrative-console","title":"Using the Kura Gateway Administrative Console","text":"The Kura Gateway Administrative Console exposes all services necessary for connecting to Everyware Cloud. The reference links listed below outline each service involved in the Everyware Cloud connection. It is recommended that each section be reviewed.
The default settings for the CloudService are typically adequate for connecting to Everyware Cloud. The screen capture shown below displays the default settings for the CloudService. For details about each setting, please refer to CloudService.
Warning
The \"Simple JSON\" payload encoding is not supported by Everyware Cloud. Use the default \"Kura Protobuf\" encoding instead.
"},{"location":"cloud-platform/kura-ec-cloud/#dataservice","title":"DataService","text":"The majority of default settings in the DataService can be left unchanged. A screen capture of the DataService configuration is shown below. For complete details about the DataService configuration parameters, please refer to DataService.
In order for Kura to connect to Everyware Cloud on startup, the connect.auto-on-startup option must be set to true
. If this value is changed from false
to true
, Kura will immediately begin the connection process. It is recommended that the CloudService and MqttDataTransport are configured before setting the connect.auto-on-startup option to true
.
Note
Changing the value of connect.auto-on-startup from true
to false
will not disconnect the client from the broker. This setting simply implies that Kura will not automatically connect on the next start of Kura.
While the majority of default settings in the MqttDataTransport can be left unchanged, the following parameters must be modified:
mqtt://broker-sbx.everyware.io:1883
account-name
username
.Note
When connecting to Everyware Cloud, the username must have proper permissions. Information on users and permissions can be found here.
For complete details about the MqttDataTransport configuration parameters, please refer to MqttDataTransport.
"},{"location":"cloud-platform/kura-ec-cloud/#connectdisconnect","title":"Connect/Disconnect","text":"The status panel can be used to manually connect or disconnect the client while Kura is running. The main button toolbar has a connect and disconnect button that may be used to control connectivity.
Note
Connecting or disconnecting the client via the status panel has no impact on Kura automatically connecting at startup. This capability is only controlled via the connect.auto-on-startup DataService setting.
"},{"location":"cloud-platform/kura-hono/","title":"Eclipse Hono\u2122 platform","text":"Eclipse Hono\u2122 provides remote service interfaces for connecting large numbers of IoT devices to a back end and interacting with them in a uniform way regardless of the device communication protocol. More information can be found here. This document outlines how to connect to Eclipse Hono using the Kura Gateway Administrative Console.
"},{"location":"cloud-platform/kura-hono/#using-the-kura-gateway-administrative-console","title":"Using the Kura Gateway Administrative Console","text":"The Kura Gateway Administrative Console exposes all services necessary for connecting to Eclipse Hono. First of all, in the Cloud Connections section, a new Hono-enabled connection needs to be setup.
From the Cloud Connections section,
the user needs to create a new connection:
by specifying a valid PID:
The result should be like the one depicted in the following image:
The reference links listed below outline each service involved in the cloud connection. It is recommended that each section be reviewed.
The default settings for the CloudService are typically adequate for connecting to a Hono instance. The screen capture shown below displays the default settings for the CloudService. For details about each setting, please refer to CloudService.
"},{"location":"cloud-platform/kura-hono/#dataservice","title":"DataService","text":"The majority of default settings in the DataService can be left unchanged. A screen capture of the DataService configuration is shown below. For complete details about the DataService configuration parameters, please refer to DataService.
In order for Kura to connect to Eclipse Hono on startup, the connect.auto-on-startup option must be set to true
. If this value is changed from false
to true
, Kura will immediately begin the connection process. It is recommended that the CloudService and MqttDataTransport are configured before setting the connect.auto-on-startup option to true
.
Note
Changing the value of connect.auto-on-startup from true
to false
will not disconnect the client from the broker. This setting simply implies that Kura will not automatically connect on the next start of Kura.
While the majority of default settings in the MqttDataTransport can be left unchanged, the following parameters must be modified:
mqtt://broker-url:1883
account-name
username
.For complete details about the MqttDataTransport configuration parameters, please refer to MqttDataTransport.
"},{"location":"cloud-platform/kura-hono/#connectdisconnect","title":"Connect/Disconnect","text":"The status panel can be used to manually connect or disconnect the client while Kura is running. The main button toolbar has a connect and disconnect button that may be used to control connectivity.
Note
Connecting or disconnecting the client via the status panel has no impact on Kura automatically connecting at startup. This capability is only controlled via the connect.auto-on-startup DataService setting.
"},{"location":"cloud-platform/kura-kapua/","title":"Eclipse Kapua\u2122 platform","text":"Eclipse Kapua\u2122 is a modular platform providing the services required to manage IoT gateways and smart edge devices. Kapua provides a core integration framework and an initial set of core IoT services including a device registry, device management services, messaging services, data management, and application enablement. More information can be found here. This document outlines how to connect to Eclipse Kapua using the Kura Gateway Administrative Console.
"},{"location":"cloud-platform/kura-kapua/#using-the-kura-gateway-administrative-console","title":"Using the Kura Gateway Administrative Console","text":"The Kura Gateway Administrative Console exposes all services necessary for connecting to Eclipse Kapua. The reference links listed below outline each service involved in the cloud connection. It is recommended that each section be reviewed.
The default settings for the CloudService are typically adequate for connecting to a Kapua instance. The screen capture shown below displays the default settings for the CloudService. For details about each setting, please refer to CloudService.
Warning
The \"Simple JSON\" payload encoding is not supported by Kapua. Use the default \"Kura Protobuf\" encoding instead.
"},{"location":"cloud-platform/kura-kapua/#dataservice","title":"DataService","text":"The majority of default settings in the DataService can be left unchanged. A screen capture of the DataService configuration is shown below. For complete details about the DataService configuration parameters, please refer to DataService.
In order for Kura to connect to Eclipse Kapua on startup, the connect.auto-on-startup option must be set to true
. If this value is changed from false
to true
, Kura will immediately begin the connection process. It is recommended that the CloudService and MqttDataTransport are configured before setting the connect.auto-on-startup option to true
.
Note
Changing the value of connect.auto-on-startup from true
to false
will not disconnect the client from the broker. This setting simply implies that Kura will not automatically connect on the next start of Kura.
While the majority of default settings in the MqttDataTransport can be left unchanged, the following parameters must be modified:
account-name
username
.For complete details about the MqttDataTransport configuration parameters, please refer to MqttDataTransport.
"},{"location":"cloud-platform/kura-kapua/#connectdisconnect","title":"Connect/Disconnect","text":"The status panel can be used to manually connect or disconnect the client while Kura is running. The main button toolbar has a connect and disconnect button that may be used to control connectivity.
Note
Connecting or disconnecting the client via the status panel has no impact on Kura automatically connecting at startup. This capability is only controlled via the connect.auto-on-startup DataService setting.
"},{"location":"cloud-platform/kura-sparkplug/","title":"Eclipse Sparkplug\u00ae Cloud Connector","text":"The org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider
package provides a Eclipse Kura Cloud Connection that implements the Eclipse Sparkplug\u00ae v3.0.0 specification.
Minimum requirements
This addon is compatible with Kura 5.2+.
"},{"location":"cloud-platform/kura-sparkplug/#introduction-to-eclipse-sparkplug","title":"Introduction to Eclipse Sparkplug","text":"from Eclipse Sparkplug
Sparkplug is an open software specification that provides MQTT clients the framework to seamlessly integrate data from their applications, sensors, devices, and gateways within the MQTT Infrastructure. It is specifically designed for use in Industrial Internet of Things (IIoT) architectures to ensure a high level of reliability and interoperability.
The specification aims fulfill the following 3 goals:
To achieve that, the Eclipse Sparkplug specification defines an architecture (see picture below) and 4 main actors:
Image from https://sparkplug.eclipse.org/specification/version/3.0/documents/sparkplug-specification-3.0.0.pdf
The main principles upon which the Specification is based on can be summarized as follows:
Connection Persistence: with the mechanisms above, the connection does not need to be persistent. For example, an Edge Node that disconnects gracefully with a MQTT DISCONNECT packet will not be seen as \"dead\" from the host application because no death certificate has been triggered (Will messages are sent only on failures). Hence, the Edge Node can implement a logic where it remains connected only during the timeframe needed for sending the new data.
Warning
This Cloud Connection maintains a persistent connection to the MQTT server.
All clients using the specification must adhere to the following topic namespace:
namespace/group_id/message_type/edge_node_id/[device_id]\n
where:
namespace
: defines the structure of the remaining elements and the encoding for the payload. With Sparkplug v3.0.0 the namespace to utilize is spBv1.0
.group_id
: some Edge Nodes can be related to each other identifying a group (for example, Edge Nodes in a given plant). This element is the identifier for the group.message_type
: defines how to interpret and handle the payload. It encapsulates the semantic of the message and can be one of the following elements:NBIRTH
/NDEATH
: Edge Node birth and death certificates.DBIRTH
/DDEATH
: Device birth and death certificates.NDATA
/DDATA
: message containing data reported by the Edge Node or Device.NCMD
/DMCD
: message containing commands for the Edge Node or Device.STATE
: message from the Primary Host Application indicating the state (offline/online) of the main consumer.edge_node_id
: the identifier for the Edge Node.device_id
(optional): the identifier for the Device. Must be unique under the same edge_node_id
and must be always present on messages belonging to Devices (D- type messages).The combination of group_id
and edge_node_id
must be unique and is called Edge Node Descriptor.
Tip
It is advised to have group_id
, edge_node_id
, and device_id
as small but as descriptive as possible, for better efficiency.
This introduction will focus more on the Edge Node and Device, as they are of more interest for this Cloud Connection.
"},{"location":"cloud-platform/kura-sparkplug/#session-management","title":"Session Management","text":"The session estabilishment procedure ensures the Edge Node to be subscribed to command-type messages for receiveing commands from the Host Application.
An Edge Node can (optionally, but incouraged) specify to be aware of a primary host application state and, in such case, it needs to subscribe to the relative STATE messages. The Edge Node will send the birth certificate (and thus completing the session init procedure) only after receiving the STATE message denoting the Primary Host Application is online. After connection, if the Edge Node receives a STATE message denoting the Primary Host Application is offline, it must restart the session estabilishment procedure.
On connection, the Edge Node sets a MQTT Will message containing a NDEATH certificate. Doing so, if the MQTT broker does not receive any communication within the Keep Alive period (client lost connection), it will send the Edge Node NDEATH certificate on all subscribers. A birth/death sequence number bdSeq
is maintained in the Edge Node to match NBIRTH with NDEATH messages in the Host Application. Each bdSeq
in the NDEATH message is matched with the corresponding bdSeq
of the previous NBIRTH message. This allows the Host Application tracking the state of the Edge Nodes and mark not up-to-date metrics as STALE.
A Device can send a device DBIRTH message after a Edge Node NBIRTH has been sent. The DBIRTH message contains all the metrics that the device will ever report on. If a new metric is added or an existing one removed, then the Device session needs to be re-estabilished. If the Edge Node looses the connection to some of its Devices, then it needs to send a Device DDEATH certificate on his behalf. The data-consuming Host Application will then mark that particular Device as offline and mark its metrics as STALE. Once the session is estabilished, the Device can publish the changed metrics using the DDATA message type.
"},{"location":"cloud-platform/kura-sparkplug/#multiple-mqtt-server-topologies","title":"Multiple MQTT Server Topologies","text":"A Primary Host Application must publish its STATE message every time it connects to the MQTT broker. This ensures the Edge Nodes to be aware of its status as long as they remain connected to the MQTT server.
At any point in time, an Edge Node can be connected to at most one MQTT server. If multiple MQTT servers are defined each time the Edge Node receives an offline STATE message from its Primary Host Application it needs to terminate the session and estabilish a new one with the next MQTT broker.
"},{"location":"cloud-platform/kura-sparkplug/#further-resources","title":"Further Resources","text":"The cloud endpoint layer allows to attach CloudPublisher
s and CloudSubscriber
s to publish/subscribe messages on Sparkplug topics.
Each CloudPublisher
attached to this cloud connection acts as a Sparkplug Device. The corresponding configuration is shown in the picture below.
The parameter specified as device.id
will dictate the Sparkplug device identifier used to publish messages from this cloud publisher. A device DBIRTH
message is immediately sent from this publisher when the first publish occurs or when a the set of published metrics is changed. The subsequent messages will be published as Sparkplug device data (DDATA
message type).
The Sparkplug Device implemented by this publisher does not support the following features (optional in the Eclipse Sparkplug specification):
tck-id-operational-behavior-device-ddeath
: Device death messages (DDEATH
message type) since the usual way to publish data from the Wire Graph using a WireAsset attached to a CloudPublisher has no implementation for reporting error states (see WireAsset.onWireReceive
)tck-id-payloads-alias-uniqueness
: Sparkplug aliases for metricstck-id-message-flow-device-dcmd-subscribe
: writing to outputs, hence it will not subscribe to device command messages (DCMD
message type)The payload of DDATA
message will be encoded using the Sparkplug B Protobuf definition converting the KuraPayload
into Sparkplug payload as follows:
Metrics from KuraPayload.metric()
become Sparkplug metrics. Only the name, timestamp, datatype and value components are added. The timestamp is set to the publishing instant. The datatype is inferred from the Java type as follows:
Boolean
DataType.Boolean
byte[]
DataType.Bytes
Double
DataType.Double
Float
DataType.Float
Byte
DataType.Int8
Short
DataType.Int16
Integer
DataType.Int32
Long
DataType.Int64
String
DataType.String
Date
DataType.DateTime
BigInteger
DataType.UInt64
All other Java types will cause the application to throw an Exception.
KuraPayload.getBody()
, if non null, will be copied into the body of the Sparkplug payload
KuraPayload.getPosition()
, if not null, will be used to create the following metrics from the KuraPosition
object, if the value in there is not null (with the corresponding Sparkplug data types):
DataType.Double
DataType.Double
DataType.Double
DataType.Double
DataType.Double
DataType.Int32
DataType.Int32
DataType.Double
DataType.DateTime
KuraPayload.getTimestamp()
, if not null, it will be used as the timestamp metric of the Sparkplug payload
This cloud connections allows creating a Cloud Subscriber that will subscribe to a generic set of topics. The configuration is shown in the picture below.
It is assumed that the payloads received by this Cloud Connection are encoded using the Sparkplug B Protobuf definition. Users of this Cloud Subscriber should expect to receive KuraMessage
s containing a KuraPayload
such that:
KuraPayload.setBody()
seq
All Sparkplug Metrics are converted into Kura metrics with the same name and the following conversion rules:
Sparkplug ValueCase Java TypeBoolean
boolean
Bytes
byte[]
Dataset
byte[]
Double
double
Extension
byte[]
Float
float
Integer
int
Long
long
String
String
Template
byte[]
default null
The metric timestamp is not supported in Eclipse Kura, therefore this information is lost at conversion.
The DataService
layer used in this component is the org.eclipse.kura.data.DataService
implementation. Please refer to the Data Service Configuraion page for further details.
The Sparkplug Data Transport layer bridges the incoming requests to the underlying Eclipse Paho MQTT v3.1.1 client following the Sparkplug specification. In particular, the Data Transport Layer ensures the following.
true
, restarts the session estabilishment procedure without sending an MQTT CONNECT packet (client connection is not closed, only BIRTH messages are re-sent).The Sparkplug Data Transport layer is configured to wait for a random period of time between 0sec and 5sec before each connection attempt. This is to ensure that, on large deployments, the target MQTT servers and Host Applications will dilute session estabilishment requests by some margin. This behavior is not part of the Sparkplug specification.
This cloud connection supports SSL connections to the connecting broker. The option SslManagerService.target allows, as an OSGi target filter, to specify the pid of the SslManagerService
instance to use for creating SSL connections for broker URIs that use the ssl://
protocol. The default socket factory is used otherwise.
As of 2.1.0 Kura provides a set of different ways to implement an application backed by Camel:
Kura provides a special \"Kura cloud endpoint\" which allows to publish or subscribe to the Kura Cloud API. The default component name for this component is kura-cloud
but it may be overridden in the following use cases.
The default component will only be registered once the default Kura Cloud API is registered with OSGi. This instance is registered with the OSGi property kura.service.pid=org.eclipse.kura.cloud.CloudService
.
If you want to publish to a different cloud service instance you can either manually register a new instance of this endpoint, or e.g. use a functionality like the Simple XML router provides: also see selecting a cloud service.
"},{"location":"cloud-platform/apache-camel-integration/kura-camel-app/#endpoint-uri","title":"Endpoint URI","text":"The URI syntax of the endpoint is (assuming the default component name): kura-cloud:appid/topic
. Where appid
is the application ID registered with the Cloud API and topic
is the topic to use.
The following URI parameters are supported by the endpoint:
Name Type Default DescriptionapplicationId
String From URI path The application ID used with the Cloud API topic
String From URI path The default topic name to publish/subscribe to when no header value is specified qos
Integer 0 The QoS value when publishing to MQTT retain
Boolean false The default retain flag when publishing to MQTT priority
Integer 5 The default priority value control
Boolean false Whether to publish/subscribe on the control or data topic hierarchy deviceId
String empty The default device ID when publishing/subscribing to control topics The following header fields are supported. If a value is not set when publishing it is taken from the endpoint configuration:
Name Type DescriptionCamelKuraCloudService.topic
String The name of the topic to publish to or from which the message was received CamelKuraCloudService.qos
Integer The QoS to use when publishing to MQTT CamelKuraCloudService.retain
Boolean The value of the retain flag when publishing to MQTT CamelKuraCloudService.control
Boolean Whether to publish/subscribe on the control or data topic hierarchy CamelKuraCloudService.deviceId
String The device ID when publishing to control topics"},{"location":"cloud-platform/apache-camel-integration/kura-camel-app/#cloud-to-cloud-messaging","title":"Cloud to cloud messaging","text":"As already described, header values override the endpoint settings. This allows for a finer grained control with Camel messaging. However this can cause unexpected behavior when two Cloud API endpoints are bridged. Camel can received from a Cloud endpoint but also publish to it. Now it is possible to write Camel routes with exchange messages, receiving from one Cloud API, pushing to another.
------------------- -------------------\n| Cloud Service A | <---> | Cloud Service B |\n------------------- -------------------\n
Which could result in a Camel route XML like:
<route id=\"bridgeLocalToRemote\">\n <from uri=\"local-cloud:sensor/sensor1\" />\n <to uri=\"upstream-cloud:gateway1/all-sensors\" />\n</route>\n
However the Consumer (from) would set the topic header value with the topic name it received the message from. And the Producer (to) would get its topic from the URI overriden by that header value.
In order to fix this behavior the header field has to be cleared before publishing:
<route id=\"bridgeLocalToRemote\">\n <from uri=\"local-cloud:sensor/sensor1\" />\n <removeHeaders pattern=\"CamelKuraCloudService.topic\"/>\n <to uri=\"upstream-cloud:gateway1/all-sensors\" />\n</route>\n
"},{"location":"cloud-platform/apache-camel-integration/kura-camel-app/#simple-xml-routes","title":"Simple XML routes","text":"Eclipse Kura 2.1.0 introduces a new \"out-of-the-box\" component which allows to configure a set of XML based routes. The component is called \"Camel XML router\" and can be configured with a simple set of XML routes.
The following example logs all messages received on the topic foo/bar
to a logger named MESSAGE_FROM_CLOUD
:
<routes xmlns=\"http://camel.apache.org/schema/spring\">\n <route id=\"cloudConsumer\">\n <from uri=\"kura-cloud:foo/bar\"/>\n <to uri=\"log:MESSAGE_FROM_CLOUD\"/>\n </route>\n</routes>\n
But it is also possible to generate data and push to upstream to the cloud service:
<route id=\"route1\">\n <from uri=\"timer:foo\"/>\n <setBody>\n <method ref=\"payloadFactory\" method=\"create('random',${random(10)})\"/>\n </setBody>\n <bean ref=\"payloadFactory\" method=\"append('foo','bar')\"/>\n <to uri=\"stream:out\"/>\n <to uri=\"kura-cloud:myapp/test\"/>\n</route>\n
This example to run a timer named \"foo\" every second. It uses the \"Payload Factory\" bean, which is pre-registered, to create a new payload structure and then append a second element to it.
The output is first sent to a logger and then to the cloud source.
"},{"location":"cloud-platform/apache-camel-integration/kura-camel-app/#defining-dependencies-on-components","title":"Defining dependencies on components","text":"It is possible to use the Web UI to define a list of Camel components which must be present in order for this configuration to work. For example if the routes make use of the \"milo-server\" adapter for providing OPC UA support then \"milo-server\" can be added and the setup will wait for this component to be registered with OSGi before the Camel context gets started.
The field contains a list of comma separated component names: e.g. milo-server, timer, log
It is also possible to define a map of cloud services which will be available for upstream connectivity. This makes use of Kura's \"multi cloud client\" feature. CloudService instances will get mapped from either a Kura Service PID (kura.service.pid
, as shown in the Web UI) or a full OSGi filter. The string is a comma seperated, key=value
string, where the key is the name of the Camel cloud the instance will be registered as and the value is the Kura service PID or the OSGi filter string.
For example: cloud=org.eclipse.kura.cloud.CloudService, cloud-2=foobar
If a standard XML route configuration is not enough then it is possible to use XML routes in combination with a custom OSGi bundle or a Java DSL based Camel approach. For this to work a Kura development setup is required, please see Getting started for more information.
The implementation of such Camel components follow the standard Kura guides for developing components, like, for example, the ConfigurableComponent
pattern. This section only describes the Camel specifics.
Of course it is also possible to follow a very simple approach and directly use the Camel OSGi functionalities like org.apache.camel.core.osgi.OsgiDefaultCamelContext
.
Note
Kura currently doesn't support the OSGi Blueprint approach
Kura support for Camel is split up in two layers. There is a more basic support, which helps in running a raw Camel router. This is CamelRunner
which is located in the package org.eclipse.kura.camel.router
. And then there are a few abstract basic components in the package org.eclipse.kura.camel.component
which help in creating Kura components based on Camel.
The base classes in org.eclipse.kura.camel.component
are intended to help creating new OSGi DS components base on Camel.
For an XML based approach which can be configured through the Kura ConfigurationService
the base class AbstractXmlCamelComponent
can be used. The constructor expectes the name of a property which will contain the Camel XML router information when it gets configured through the configuration service. It will automatically parse and apply the Camel routes.
The method void beforeStart(CamelContext camelContext)
may be used in order to configure the Camel context before it gets started.
Every time the routes get updated using the modified(Map<String, Object>)
method, the route XML will be re-parsed and routes will be added, removed or updated according to the new XML.
In order to create a Java DSL based router setup the base class AbstractJavaCamelComponent
may be used, which implements and RouteBuilder
class, a simple setup might look like:
import org.eclipse.kura.camel.component.AbstractJavaCamelComponent;\n\nclass MyRouter extends AbstractJavaCamelComponent {\n public void configure() throws Exception {\n from(\"direct:test\")\n .to(\"mock:test\");\n }\n}\n
"},{"location":"cloud-platform/apache-camel-integration/kura-camel-app/#using-the-camelrunner","title":"Using the CamelRunner","text":"The CamelRunner
class is not derived from any OSGi or Kura base class and can be used in scenarios where more flexibility is required. It allows to define a set of pre-requisites for the Camel context. It is for example possible to define a dependency on a Kura cloud service instance and a Camel component provider. Once the runner is started it will listen for OSGi services resolving those dependencies and then starting up the Camel context. The following example shows how to set up a Camel context using the CamelRunner
:
// create a new camel Builder\n\nBuilder builder = new CamelRunner.Builder();\n\n// add service dependency\n\nbuilder.cloudService(\"kura.service.pid\", \"my.cloud.service.pid\");\n\n// add Camel component dependency to 'milo-server'\n\nbuilder.requireComponent(\"milo-server\");\n\nCamelRunner runner = builder.build();\n\n// set routes\n\nrunner.setRoutes ( new RouteBuilder() {\n public void configure() throws Exception {\n from(\"direct:test\")\n .to(\"mock:test\");\n }\n} );\n\n// set routes\n\nrunner.start ();\n
It is also possible to later update routes with a call to setRoutes
:
// maybe update routes at a later time\n\nrunner.setRoutes ( /* different routes */ );\n
"},{"location":"cloud-platform/apache-camel-integration/kura-camel-app/#examples","title":"Examples","text":"The following examples can help in getting started.
"},{"location":"cloud-platform/apache-camel-integration/kura-camel-app/#kura-camel-example-publisher","title":"Kura Camel example publisher","text":"The Camel example publisher (org.eclipse.kura.example.camel.publisher
) can be used as an reference for starting. The final OSGi bundle can be dropped into a Kura application an be started. It allows to configure dynamically during runtime and is capable of switching CloudService instances dynamically.
The Camel quickstart project (org.eclipse.kura.example.camel.quickstart
) shows two components, Java and XML based, working together. The bundle can also be dropped into Kura for testing.
The Camel quickstart project (org.eclipse.kura.example.camel.aggregation
) shows a simple data aggregation pattern with Camel by processing data and publishing the result.
The default way to create a new cloud service instance backed by Camel is to use the new Web UI for cloud services. A new cloud service instance of the type org.eclipse.kura.camel.cloud.factory.CamelFactory
has to be created. In addition to that a set of Camel routes have to be provided.
The interface with the Kura application is the Camel vm
component. Information set \"upstream\" from the Kura application can be received by the Camel cloud service instance of the following endpoint vm:camel:example
. Where camel
is the application id and example
is the topic.
The following code snippet writes out all of the Kura payload structure received on this topic to the logger system:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<routes xmlns=\"http://camel.apache.org/schema/spring\">\n\n <route id=\"camel-example-topic\">\n <from uri=\"vm:camel:example\"/>\n <split>\n <simple>${body.metrics().entrySet()}</simple>\n <setHeader headerName=\"item\">\n <simple>${body.key()}</simple>\n </setHeader>\n <setBody>\n <simple>${body.value()}</simple>\n </setBody>\n <toD uri=\"log:kura.data.${header.item}\"/>\n </split>\n </route>\n\n</routes>\n
The snippet splits up the incoming KuraPayload structure and creates a logger called kura.data.<metric>
for each metric and writes out the actual value to it. The output in the log file should look like:
2016-11-14 16:14:34,539 [Camel (camel-10) thread #18 - vm://camel:example] INFO k.d.intValue - Exchange[ExchangePattern: InOnly, BodyType: Long, Body: 19]\n2016-11-14 16:14:34,566 [Camel (camel-10) thread #18 - vm://camel:example] INFO k.d.doubleValue - Exchange[ExchangePattern: InOnly, BodyType: Double, Body: 10.226808617581144]\n2016-11-14 16:14:35,575 [Camel (camel-10) thread #18 - vm://camel:example] INFO k.d.intValue - Exchange[ExchangePattern: InOnly, BodyType: Long, Body: 19]\n2016-11-14 16:14:35,602 [Camel (camel-10) thread #18 - vm://camel:example] INFO k.d.doubleValue - Exchange[ExchangePattern: InOnly, BodyType: Double, Body: 10.27218775669447]\n2016-11-14 16:14:36,539 [Camel (camel-10) thread #18 - vm://camel:example] INFO k.d.intValue - Exchange[ExchangePattern: InOnly, BodyType: Long, Body: 19]\n2016-11-14 16:14:36,567 [Camel (camel-10) thread #18 - vm://camel:example] INFO k.d.doubleValue - Exchange[ExchangePattern: InOnly, BodyType: Double, Body: 10.314456684208022]\n
"},{"location":"cloud-platform/apache-camel-integration/kura-camel/","title":"Apache Camel\u2122 integration overview","text":"Note
This document describes the Camel integration for Kura 2.1.0
Kura provides two main integration points for Camel:
The first allows one to configure Camel to provide data and receive commands from any CloudService instance which is configured in Kura. For example the default CloudService instance which is backed by MQTT.
The second approach allows one to create a custom CloudService implementation and route data coming from other Kura applications with the routes provided by this Camel context.
"},{"location":"cloud-platform/apache-camel-integration/kura-camel/#deploying-additional-camel-components","title":"Deploying additional Camel components","text":"Kura comes with the following Camel components pre-installed:
camel-core
camel-core-osgi
camel-stream
If additional Camel components are required, they can be installed using deployment packages (DP), as common with Kura.
There are pre-packaged DPs available for e.g. AMQP, OPC UA, MQTT and other Camel components outside of the Kura project.
"},{"location":"connect-field-devices/IO-apis/","title":"I/O APIs","text":"The full Eclipse Kura API reference is available here.
In this page, the developer can find a synthetic grouping of the I/O APIs added starting from Kura 3.1.0.
Drivers
Assets
An Asset is a logical representation of a field device, described by a list of Channels. The Asset uses a specific Driver instance to communicate with the underlying device and it models a generic device resource as a Channel. A register in a PLC or a GATT Characteristic in a Bluetooth device are examples of Channels. In this way, each Asset has multiple Channels for reading and writing data from/to an Industrial Device.
Assets can be used as Wire Components to access the resources referenced by the defined channels inside a Wire Graph, see the Assets as Wire Components guide for more details.
"},{"location":"connect-field-devices/asset-implemetation/#channel-example","title":"Channel Example","text":"To further describe the concept of Channel and Asset, the following table shows a set of PLC register addresses as provided in a typical PLC documentation.
Name Entity Address LED1 COILS 2049 LED2 COILS 2050 LED3 COILS 2051 LED4 RED COILS 2052 LED4 GREEN COILS 2053 LED4 BLUE COILS 2054 Counter 3 INPUT REGISTERS 515 Quad Counter INPUT REGISTERS 520 Toggle 4 DISCRETE INPUTS 2052 Toggle 5 DISCRETE INPUTS 2053 Toggle 6 DISCRETE INPUTS 2054 Reset Counter 3 COILS 3075 Reset Quad Counter COILS 3084The corresponding Channels definition in the Asset is as follows:
As shown in the previous image, the Channel definition in an Asset results easily mappable to what available in a generic PLC documentation.
Once defined the Channels in an Asset, a simple Java application that leverages the Asset API can easily communicate with the Field device by simply referring to the specific Channel of interest.
"},{"location":"connect-field-devices/asset-implemetation/#channel-definition","title":"Channel Definition","text":"For the READ and READ/WRITE channels, the Asset typically asks the driver to provide a value based on the value.type. If the scaleoffset.type is LONG or DOUBLE, the type requested will be one of these and the final value (after the scale and offset operation) will be transformed into the data type expected by value.type.
"},{"location":"connect-field-devices/asset-implemetation/#arithmetic-with-scale-and-offset","title":"Arithmetic with scale and offset","text":"The Asset supports applying a scale and offset to the values obtained by the attached Driver during read operations and to the values received in listen mode.
Warning
Application of scale and offset for write operations is not supported.
The following modes are implemented for computing scale and offset:
DOUBLE
INTEGER
LONG
FLOAT
The values of the scale and offset configuration parameters and the value obtained from the Driver are all converted to the mode type using the Java casting and then the following operation is performed: channel_value * scale + offset
. The operation result is casted again to value.type to produce the final channel value.
The values of the scale and offset parameters are parsed from channel configuration as doubles.
The mode can be selected in the following way:
DOUBLE
or LONG
the corrisponding mode will be used. The largest representable LONG
is 2^53DEFINED_BY_VALUE_TYPE
the operation mode is determinated by value.type.Example of DOUBLE
mode: channel configured with:
DOUBLE
Since scaleoffset.type is DOUBLE
, the scale and offset mode is forced to DOUBLE
.
If channel_value
is 5 (INTEGER) the result is: (int) ((double) channel_value * (double) 3.25d + (double) 1.5d) = 17
.
Example of INTEGER
mode: channel configured with:
DEFINED_BY_VALUE_TYPE
Since scaleoffset.type is DEFINED_BY_VALUE_TYPE
, the mode determined by the value.type parameter (INTEGER
) will be used.
If channel_value
is 5 (INTEGER) the result is: (int) (channel_value * (int) 3.25d + (int) 1.5d) = 16
.
Example of DOUBLE
mode: channel configured with:
DEFINED_BY_VALUE_TYPE
If channel_value
is 5 (DOUBLE) the result is: (double) (channel_value * (double) 3.25d + (double) 1.5d) = 17.75
.
Warning
If the mode is LONG
or INTEGER
the decimal part of the scale and offset value will be discarded.
As the examples show the final result can be different depending on the used mode and value.type.
"},{"location":"connect-field-devices/asset-implemetation/#driver-specific-parameters","title":"Driver specific parameters","text":"The parameters that are not included in list of driver independent parameters above are driver specific. These parameters are used to identify the resource addressed by the channel.
Driver specific parameters are described in the driver documentation.
"},{"location":"connect-field-devices/asset-implemetation/#other-asset-configurations","title":"Other Asset Configurations","text":"The creation of the channels is a process that could be very time and effort consuming. For this reason, once the user has created the desired channels, it is possible to download the entire list from the web UI, by clicking the Download Channels
button:
The list is downloaded in csv format and is represented in the form of a table, whose columns represent the entries for the options in the channel definition, while each row is equivalent to a specific channel. For example, the resulting csv file retrieved from downloading the list of channels in the image above is:
The resulting table is composed by some static, pre-defined options (the ones mentioned in Channel Definition section above, from enabled
to listen
) that are the same for each component and the ones introduced by the specific bundle under analisys. In this case, the modbus driver introduces these driver-specific options:
The download tool is extremely useful in all those situations where the user wants to quickly load a long list of channels at once: for example, it can easily clone the same list in multiple assets, export it to another device, or simply save it locally to always have a copy of the channels ready.
"},{"location":"connect-field-devices/asset-implemetation/#csv-upload","title":"CSV upload","text":"The Upload Channels
button allows the user to load a local csv file to create the channel list in one shot: the uploading file must implement the same table-structure described in the \"Channels download\" section above, so with each rows representing a channels, and each column one entry of the channel's options.
Once the user clicks on the button, will be shown a pop-up in which there are a button to locate the file in the user's filesystem and two checkboxes to allow the uploading phase customization. After clicking on Upload
, if the process is succesful, the new channels list will be shown, and the user is just asked to click on the Apply
button to save the asset variation.
The Force import empty string policy
checkbox forces the parsing of all empty values present in the csv as empty strings, for all those channel's options that are typed to String and \"not required\" by the metatype.
So, this box must be checked when the user wants that all empty values from the csv are considered as empty strings (\"\"
) when parsed to driver-specific channel option, defined by the metatype as String type and not required. So, those values that are null
in the csv, will be set as \"\"
in the channel options. The user must be cautious, because the framework supposes that it's consciously leaving empty values in the csv.
Otherwise, if the box is unchecked, all the csv empty values will be considered as null
strings and parsed to the default value set in the metatype of the driver.
If, for example, the user downloads the channels list following the steps described in the precious section, it could upload the same csv file into an other asset, or another device, to get the exactly same asset configuration.
"},{"location":"connect-field-devices/asset-implemetation/#replace-current-channels","title":"Replace current channels","text":"The Replace current channels
must be checked when the user wants to replace all the channels currently present in the asset, with the ones that will be created by the csv uploading.
The ASSET-V1 namespace allows to perform remote operations on the assets defined in an Kura-powered device. The requests and responses are represented as JSON arrays placed in the body of the MQTT payload.
The namespace includes the following topics.
"},{"location":"connect-field-devices/asset-v1-mqtt-namespace/#getassets","title":"GET/assets","text":"This topic is used to retrieve metadata describing the assets defined on a specific device and their channel configuration.
"},{"location":"connect-field-devices/asset-v1-mqtt-namespace/#request-format","title":"Request format","text":"The request can contain JSON array containing a list of asset names for which the metadata needs to be returned. The request JSON must have the following structure:
[\n {\n \"name\": \"asset1\"\n },\n {\n \"name\": \"otherAsset\"\n }\n]\n
The request JSON is an array with all elements of the type object
. The array object has the following properties:
If the provided array is empty or the request payload is empty, the metadata describing all assets present on the device will be returned.
"},{"location":"connect-field-devices/asset-v1-mqtt-namespace/#response-format","title":"Response format","text":"The response payload contains a JSON array with the following structure:
[\n {\n \"name\": \"asset1\",\n \"channels\": [\n {\n \"name\": \"first_channel\",\n \"type\": \"INTEGER\",\n \"mode\": \"READ\"\n },\n {\n \"name\": \"second_channel\",\n \"type\": \"BOOLEAN\",\n \"mode\": \"READ_WRITE\"\n },\n {\n \"name\": \"other_channel\",\n \"type\": \"STRING\",\n \"mode\": \"WRITE\"\n }\n ]\n },\n {\n \"name\": \"otherAsset\",\n \"channels\": []\n },\n {\n \"name\": \"nonExistingAsset\",\n \"error\": \"Asset not found\"\n }\n]\n
All elements of the array are of the type object
. The array object has the following properties:
error
property are mutually exclusive. This object is an array with all elements of the type object
and they have the following properties:READ
, WRITE
or READ_WRITE
.BOOLEAN
, BYTE_ARRAY
, DOUBLE
, INTEGER
, LONG
, FLOAT
, STRING
.This topic is used to perform a read operation on a specified set of assets and channels.
"},{"location":"connect-field-devices/asset-v1-mqtt-namespace/#request-format_1","title":"Request format","text":"The request can contain a JSON array with the following structure:
[\n {\n \"name\": \"asset1\",\n \"channels\": [\n {\n \"name\": \"channel1\"\n },\n {\n \"name\": \"channel2\"\n },\n {\n \"name\": \"otherChannel\"\n }\n ]\n },\n {\n \"name\": \"otherAsset\"\n }\n]\n
The request JSON is an array with all elements of the type object
. If the list is empty or if the request payload is empty all channels of all assets will be read. The array object has the following properties:
object
. The array object has the following properties:The response is returned as a JSON array placed in the body of the response:
[\n {\n \"name\": \"asset1\",\n \"channels\": [\n {\n \"name\": \"first_channel\",\n \"type\": \"INTEGER\",\n \"value\": \"432\",\n \"timestamp\": 1234550\n },\n {\n \"name\": \"second_channel\",\n \"type\": \"BOOLEAN\",\n \"value\": \"true\",\n \"timestamp\": 1234550\n },\n {\n \"name\": \"other_channel\",\n \"error\": \"Read failed\",\n \"timestamp\": 1234550\n },\n {\n \"name\": \"binary_channel\",\n \"type\": \"BYTE_ARRAY\",\n \"value\": \"dGVzdCBzdHJpbmcK\",\n \"timestamp\": 1234550\n }\n ]\n },\n {\n \"name\": \"nonExistingAsset\",\n \"error\": \"Asset not found\"\n }\n]\n
The response JSON is an array with all elements of the type object
. The array object has the following properties:
object
. The array object has the following properties:BOOLEAN
, BYTE_ARRAY
, DOUBLE
, INTEGER
, LONG
, FLOAT
, STRING
.BYTE_ARRAY
, the result will be represented using the base64 encoding.Performs a write operation on a specified set of channels and assets.
"},{"location":"connect-field-devices/asset-v1-mqtt-namespace/#request-format_2","title":"Request format","text":"The request must contain a JSON array with the following structure:
[\n {\n \"name\": \"asset1\",\n \"channels\": [\n {\n \"name\": \"first_channel\",\n \"type\": \"INTEGER\",\n \"value\": \"432\",\n },\n {\n \"name\": \"second_channel\",\n \"type\": \"BOOLEAN\",\n \"value\": \"true\",\n },\n {\n \"name\": \"binary_channel\",\n \"type\": \"BYTE_ARRAY\",\n \"value\": \"dGVzdCBzdHJpbmcK\",\n }\n ]\n }\n]\n
The array object has the following properties:
object
. The array object has the following properties:BOOLEAN
, BYTE_ARRAY
, DOUBLE
, INTEGER
, LONG
, FLOAT
, STRING
.The response uses the same format as the EXEC/read
request, in case of success the type and value properties in the response will report the same values specified in the request.
Eclipse Kura introduces a model based on the concepts of Drivers and Assets to simplify the communication with the field devices attached to a gateway.
A Driver encapsulates the communication protocol and its configuration parameters, dealing with the low-level characteristics of the field protocol. It opens, closes and performs the communication with the end field device. It also exposes field protocol specific information that can be used by upper levels of abstraction to simplify the interaction with the end devices.
An Asset is a logical representation of a field device, described by a list of Channels. The Asset uses a specific Driver instance to communicate with the underlying device and it models a generic device resource as a Channel. A register in a PLC or a GATT Characteristic in a Bluetooth device are examples of Channels. In this way, each Asset has multiple Channels for reading and writing data from/to an Industrial Device.
"},{"location":"connect-field-devices/driver-and-assets/#channel-example","title":"Channel Example","text":"To further describe the concept of Channel and Asset, the following table shows a set of PLC register addresses as provided in a typical PLC documentation.
Name Entity Address LED1 COILS 2049 LED2 COILS 2050 LED3 COILS 2051 LED4 RED COILS 2052 LED4 GREEN COILS 2053 LED4 BLUE COILS 2054 Counter 3 INPUT REGISTERS 515 Quad Counter INPUT REGISTERS 520 Toggle 4 DISCRETE INPUTS 2052 Toggle 5 DISCRETE INPUTS 2053 Toggle 6 DISCRETE INPUTS 2054 Reset Counter 3 COILS 3075 Reset Quad Counter COILS 3084The corresponding Channels definition in the Asset is as follows:
As shown in the previous image, the Channel definition in an Asset results easily mappable to what available in a generic PLC documentation.
Once defined the Channels in an Asset, a simple Java application that leverages the Asset API can easily communicate with the Field device by simply referring to the specific Channel of interest.
"},{"location":"connect-field-devices/driver-and-assets/#drivers-and-assets-in-kura-administrative-ui","title":"Drivers and Assets in Kura Administrative UI","text":"Kura provides a specific section of the UI to allow users to manage the different instances of Drivers and Assets. Using the Kura Web UI the user can instantiate and manage Drivers
but also can manage Assets instances based on existing drivers.
The user interface allows also to perform specific reads on the configured Assets' channels clicking on the Data tab for the selected Asset.
"},{"location":"connect-field-devices/driver-implemetation/","title":"Driver implementation","text":"A Driver encapsulates the communication protocol and its configuration parameters.
The Driver API abstracts the specificities of the end Fieldbus protocols providing a clean and easy to use set of calls that can be used to develop end-applications.
Using the Driver APIs, an application can simply use the connect and disconnect methods to open or close the connection with the Field device. Furthermore, the read and write methods allow exchanging data with the Field device.
A Driver instance can be associated with an Asset to abstract even more the low-level specificities and allow an easy and portable development of the Java applications that need to interact with sensors, actuators, and PLCs.
The Asset will use the Driver's protocol-specific channel descriptor to compose the Asset Channel description.
"},{"location":"connect-field-devices/driver-implemetation/#driver-configuration","title":"Driver Configuration","text":"Generally, a Driver instance is a configurable component which parameters can be updated in the Drivers and Assets section of the Kura Administrative User Interface.
"},{"location":"connect-field-devices/driver-implemetation/#supported-field-protocols-and-availability","title":"Supported Field Protocols and Availability","text":"Drivers will be provided as add-ons available in the Eclipse IoT Marketplace. Please see here for a complete list.
"},{"location":"connect-field-devices/driver-implemetation/#driver-specific-optimizations","title":"Driver-Specific Optimizations","text":"The Driver API provides a simple method to read a list of Channel Records:
public void read(List<ChannelRecord> records) throws ConnectionException;\n
Typically, since the records to read do not change until the Asset configuration is changed by the user, a Driver can perform some optimisations to efficiently read the requested records at once. For example, a Modbus driver can read a range of holding registers using a single request.
Since these operations are costly, the Kura API adds methods to ask the driver to prepare reading a given list of records and execute the prepared read:
public PreparedRead prepareRead(List<ChannelRecord> records);\n
Invocation of the preparedRead method will result in a PreparedRead instance returned.
On a PreparedRead, the execute method will perform the optimized read request.
"},{"location":"connect-field-devices/eddystone-driver/","title":"Eddystone\u2122 Driver","text":"Eclipse Kura offers support for Eddystone\u2122 protocol via a specific driver. The driver is available only for gateways that support the new Bluetooth LE APIs. It can be used into the Wires framework, the Asset model or directly using the Driver itself.
"},{"location":"connect-field-devices/eddystone-driver/#features","title":"Features","text":"The Eddystone\u2122 driver is designed to listen for incoming beacon packets and to recognise the specific protocol. Of course it's not possible to write data to the beacons, since this is outside the protocol specification. The frame format to be filtered can be chosen from the channel definition. For more information about Eddystone\u2122 frame format, see here.
"},{"location":"connect-field-devices/eddystone-driver/#installation","title":"Installation","text":"As the others Drivers supported by Eclipse Kura, it is distributed as a deployment package on the Eclipse Marketplace here. It can be installed following the instructions provided here.
"},{"location":"connect-field-devices/eddystone-driver/#instance-creation","title":"Instance creation","text":"A new Eddystone Driver instance can be created either by clicking the New Driver button in the dedicated Drivers and Assets Web UI section or by clicking on the +
button under Services. In both cases, the org.eclipse.kura.driver.eddsytone
factory must be selected and a unique name must be provided for the new instance. Once instantiated, the Driver has to be configured setting the Bluetooth interface name (i.e. hci0
) that will be used to connect to the device.
The Eddystone Driver channel can be configured with the following parameters:
READ
, WRITE
, or READ_WRITE
).UID
and URL
typed are supported.Eclipse Kura provides support for field protocol implementations as add-ons deployable directly from the Eclipse Marketplace for IoT site. Moreover, several devices are supported using the Kura Driver model.
Currently, the following field protocols and devices are supported and downloadable from the Eclipse Marketplace in form of Kura Drivers:
Protocol/Device Kura 3.x Kura 4.x Kura 5.x OPC-UA link link link S7 link link link iBeacon N.A. link link Eddystone N.A. link link TiSensorTag link link link GPIO link link link SenseHat link link link"},{"location":"connect-field-devices/gpio-driver/","title":"GPIO Driver","text":"The GPIO Driver manages the General Purpose IOs on a gateway using the Driver model. Based on the GPIO Service, the driver can be used in the Wires framework, the Asset model or directly using the Driver itself.
"},{"location":"connect-field-devices/gpio-driver/#features","title":"Features","text":"The GPIO Driver includes the following features:
As the other Drivers supported by Eclipse Kura, it is distributed as a deployment package on the Eclipse Marketplace for Kura 3.x and 4.x/5.x. It can be installed following the instructions provided here.
"},{"location":"connect-field-devices/gpio-driver/#instance-creation","title":"Instance creation","text":"A new GPIO Driver instance can be created either by clicking the New Driver button in the dedicated Drivers and Assets Web UI section or by clicking on the + button under Services. In both cases, the org.eclipse.kura.driver.gpio
factory must be selected and a unique name must be provided for the new instance. Once instantiated, the GPIO Driver is ready to use and no configuration is needed.
The GPIO Driver channel can be configured with the following parameters:
READ
, WRITE
, or READ_WRITE
).#select resource
selection has no effect on the channel.INPUT
and OUTPUT
. The #select direction
selection has no effect on the channel.resource.trigger: the type of event that triggers the listener, if selected. Possible values are:
NONE
: no event will trigger the listener.
RISING_EDGE
, FALLING_EDGE
, BOTH_EDGES
: the listeners will be triggered respectively by a low-high transition, a high-low transition or both.HIGH_LEVEL
,LOW_LEVEL
, BOTH_LEVELS
: the listeners will be triggered respectively by the detection of a high, low or both levels. Please note that these options aren't supported by all the devices.In this section a simple example on the GPIO Driver using a RaspberryPi will be presented. Before configuring the Driver, arrange a setup as shown in the following picture, using a breadboard, a led, a 120-ohm resistor and some wires. Connect the yellow wire to a ground pin on the RasperryPi connector (i.e. pin 6) and the red one to pin 40 (a.k.a. gpio21).
From the Drivers and Assets tab, create a new GPIO Driver, call it GPIODriver and add an Asset as shown in the following picture.
The asset is configured to manage a gpio, called LED, as an output and drives it writing a boolean value. The LED channel is attached to the gpio21 on the RaspberryPi. In the Data tab, fill the Value form with true and press Apply: the green led will switch on. Writing a false will switch off the led.
"},{"location":"connect-field-devices/ibeacon-driver/","title":"iBeacon\u2122 Driver","text":"Eclipse Kura provides a driver specifically developed to manage iBeacon\u2122 protocol. The driver is available only for gateways that support the new Bluetooth LE APIs. They can be used into the Wires framework, the Asset model or directly using the Driver itself.
"},{"location":"connect-field-devices/ibeacon-driver/#features","title":"Features","text":"The iBeacon\u2122 driver is designed to listen for incoming beacon packets and to recognise the specific protocol. Of course it's not possible to write data to the beacons, since this is outside the protocol specification.
"},{"location":"connect-field-devices/ibeacon-driver/#installation","title":"Installation","text":"As the others Drivers supported by Eclipse Kura, it is distributed as a deployment package on the Eclipse Marketplace here. It can be installed following the instructions provided here.
"},{"location":"connect-field-devices/ibeacon-driver/#instance-creation","title":"Instance creation","text":"A new iBeacon instance can be created either by clicking the New Driver button in the dedicated Drivers and Assets Web UI section or by clicking on the +
button under Services. In both cases, the org.eclipse.kura.driver.ibeacon
factory must be selected and a unique name must be provided for the new instance. Once instantiated, the Driver has to be configured setting the Bluetooth interface name (i.e. hci0
) that will be used to connect to the device.
The iBeacon Driver channel can be configured with the following parameters:
READ
, WRITE
, or READ_WRITE
).This Driver implements the client side of the OPC UA protocol using the Driver model. The Driver can be used to interact as a client with OPC UA servers using different abstractions, such as the Wires framework, the Asset model or by directly using the Driver itself.
The Driver is distributed as a deployment package on Eclipse Marketplace for Kura 3.x and 4.x/5.x. It can be installed following the instructions provided here.
"},{"location":"connect-field-devices/opcua-driver/#features","title":"Features","text":"The OPC UA Driver features include:
A new OPC UA instance can be created either by clicking the New Driver button in the dedicated Drivers and Assets Web UI section or by clicking on the + button under Services. In both cases, the org.eclipse.kura.driver.opcua
factory must be selected and a unique name must be provided for the new instance.
The OPC UA Driver channel configuration is composed of the following parameters:
READ
, WRITE
, or READ_WRITE
).opcua.type: The OPC-UA built-in type of the attribute to be read/written. If set to DEFINED_BY_JAVA_TYPE (default), the driver will attempt to determine the OPC-UA type basing on the value type parameter value. If the read/write operation fails, it may be necessary to use one of the other values of this configuration parameter to explicitly select the type.
This parameter also lists the OPC-UA types currently supported by the driver.
Not all value type and opcua.type combinations are valid, the allowed ones are the following:
opcua.type Allowed value.types Recommended value.type BOOLEAN BOOLEAN BOOLEAN SBYTE INTEGER, LONG, FLOAT, DOUBLE, STRING INTEGER INT16 INTEGER, LONG, FLOAT, DOUBLE, STRING INTEGER INT32 INTEGER, LONG, FLOAT, DOUBLE, STRING INTEGER INT64 INTEGER, LONG, FLOAT, DOUBLE, STRING LONG BYTE INTEGER, LONG, FLOAT, DOUBLE, STRING INTEGER UINT16 INTEGER, LONG, FLOAT, DOUBLE, STRING INTEGER UINT32 INTEGER, LONG, FLOAT, DOUBLE, STRING LONG UINT64 INTEGER, LONG, FLOAT, DOUBLE, STRING STRING FLOAT FLOAT, STRING FLOAT DOUBLE DOUBLE, STRING DOUBLE STRING STRING STRING BYTE_STRING BYTE_ARRAY BYTE_ARRAY BYTE_ARRAY BYTE_ARRAY BYTE_ARRAY SBYTE_ARRAY BYTE_ARRAY BYTE_ARRAYUsing a non allowed value.type will result in read/write operation failures. It should be noted that there is not a one to one match between the opcua.type and Java value.type. It is recommended to compare the allowed ranges for numeric types specified in OPC-UA Reference and Java reference for selecting the best match.
node.id.type: The type of the node id (see the Node Id types section)
If the listen flag is enabled for an OPC-UA channel, the driver will request the server to send notifications if it detects changes in the referenced attribute value.
In order to enable this, the driver will create a global subscription (one per Driver instance), and a monitored item for each channel. See [1] for more details. The Subscription publish interval global configuration parameter can be used to tune the subscription publishing interval.
The listen.subscribe.to.children parameter can be used to enable the Subtree Subscription feature.
[1] MonitoredItem model
"},{"location":"connect-field-devices/opcua-driver/#node-id-types","title":"Node ID types","text":"The Driver supports the following node id types:
Node ID Type Format of node.id NUMERIC node.id must be parseable into an integer STRING node.id can be any string OPAQUE Opaque node ids are represented by raw byte arrays. In this case node.id must be the base64 encoding of the node id. GUID node.id must be a string conforming to the format described in the documentation of the java.util.UUID.toString() method."},{"location":"connect-field-devices/opcua-driver/#certificate-setup","title":"Certificate setup","text":"In order to use settings for Security Policy different than None, the OPCUA driver must be configured to trust the server certificate and a new client certificate - private key pair must be generated for the driver. These items can be placed in a Java keystore that can be referenced from driver configuration. The keystore does not exist by default and without it connections that use Security Policy different than None will fail.
The following steps can be used to generate the keystore:
Copy the following example script to the device using SSH, it can be used to import the server certificate and generate the client key pair. It can be modified if needed:
#!/bin/bash\n\n# the alias for the imported server certificate\nSERVER_ALIAS=\"server-cert\"\n\n# the file name of the generated keystore\nKEYSTORE_FILE_NAME=\"opcua-keystore.ks\"\n# the password of the generated keystore and private keys, it is recommended to change it\nKEYSTORE_PASSWORD=\"changeit\"\n\n# server certificate to be imported is expected as first argument\nSERVER_CERTIFICATE_FILE=\"$1\"\n\n# import existing certificate\nkeytool -import \\\n -alias \"${SERVER_ALIAS}\" \\\n -file \"${SERVER_CERTIFICATE_FILE}\" \\\n -keystore \"${KEYSTORE_FILE_NAME}\" \\\n -noprompt \\\n -storepass \"${KEYSTORE_PASSWORD}\"\n\n# alias for client certificate\nCLIENT_ALIAS=\"client-cert\"\n# client certificate distinguished name, it is recommended to change it \nCLIENT_DN=\"CN=MyCn, OU=MyOu, O=MyOrganization, L=Amaro, S=UD, C=IT\"\n# the application id, must match the corresponding parameter in driver configuration\nAPPLICATION_ID=\"urn:kura:opcua:client\"\n\n# generate the client private key and certificate\nkeytool -genkey \\\n -alias \"${CLIENT_ALIAS}\" \\\n -keyalg RSA \\\n -keysize 4096 \\\n -keystore \"${KEYSTORE_FILE_NAME}\" \\\n -dname \"${CLIENT_DN}\" \\\n -ext ku=digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment \\\n -ext eku=clientAuth \\\n -ext \"san=uri:${APPLICATION_ID}\" \\\n -validity 1000 \\\n -noprompt \\\n -storepass ${KEYSTORE_PASSWORD} \\\n -keypass ${KEYSTORE_PASSWORD}\n
Update the following parameters in driver configuration:
opcua-keystore.ks
file created at step 3.CLIENT_ALIAS
script variable (the default is client-cert
) KEYSTORE_PASSWORD
script variable (the default value is changeit
)Application URI -> Set the value of the APPLICATION_ID
script variable (default value should be already ok).
Configurare the server to trust the client certificate generated at step 3. The steps required to do this vary depending on the server. Usually the following steps are needed:
The driver can be configured to recursively visit the children of a folder node and create a Monitored Item for the value of each discovered variable node with a single channel in Asset configuration.
Warning: This feature should be used with care since it can cause high load on both the gateway and the server if the referenced folder contains a large number of nodes and/or the notification rate is high.
"},{"location":"connect-field-devices/opcua-driver/#channel-configuration_1","title":"Channel configuration","text":"In order to configure the driver to perform the discovery operation, a single channel can be defined with the following configuration:
READ
STRING
(see below)true
true
The rest of the configuration parameters can be specified in the same way as for the single node subscription use case.
The listen.sampling.interval, listen.queue.size and listen.discard.oldest parameters of the root will be used for all subscriptions on the subtree.
"},{"location":"connect-field-devices/opcua-driver/#discovery-procedure","title":"Discovery procedure","text":"The driver will consider as folders to visit all nodes that whose type definition is FolderType
, or more precisely all nodes with the following reference:
HasTypeDefinition
: * namespace index: 0 * node id: 61 (numeric) * URN: http://opcfoundation.org/UA/
The driver will subscribe to all the variable nodes found.
"},{"location":"connect-field-devices/opcua-driver/#event-reporting","title":"Event reporting","text":"If the Driver is used by a Wire Asset, it will emit on the wire a single message per received event.
All emitted events will contain a single property. Depending on the value of the Subtree subscription events channel name format global configuration parameter, the name of this property is the node id or the browsed path of the source OPCUA node relative to the root folder defined in the channel configuration.
"},{"location":"connect-field-devices/opcua-driver/#type-conversion","title":"Type conversion","text":"The current version of the driver tries to convert the values received for all the events on a subtree to the type defined in the value.type configuration parameter.
Since the value types of the discovered nodes are heterogeneous, the conversion might fail if the types are not compatible (e.g. if value.type is set to INTEGER
and the received value is a string).
Setting value.type to STRING
should allow to perform safe conversions for most data types.
This Driver implements the s7comm protocol and can be used to interact with Siemens S7 PLCs using different abstractions, such as the Wires framework, the Asset model or by directly using the Driver itself.
The Driver is distributed as a deployment package on the Eclipse Marketplace for Kura 3.x and 4.x/5.x. It can be installed following the instructions provided here.
"},{"location":"connect-field-devices/s7-driver/#features","title":"Features","text":"The S7comm Plc Driver features include:
A new S7comm driver instance can be created either by clicking the New Driver button in the dedicated Drivers and Assets Web UI section or by clicking on the + button under Services. In both cases, the org.eclipse.kura.driver.s7plc
factory must be selected and a unique name must be provided for the new instance.
The S7 Driver channel configuration is composed of the following parameters:
READ
, WRITE
, or READ_WRITE
).STRING
or BYTE_ARRAY
. In the other cases, this parameter is ignored and the data size is automatically derived from the s7.data.type.BOOLEAN
and s7.data.type is set to BOOL
. In the other cases, this parameter is ignored.When performing operations that deal with numeric data, two data types are involved:
The Java primitive type that is used in the ChannelRecords exchanged between the driver and Java applications. (the Java type of the value received/supplied by external applications from/to the Driver in case of a read/write operation). This value type is specified by the value type configuration property.
The S7 type of the data on the PLC. This value type is specified by the s7.data.type configuration property. The following S7 data types are supported:
S7 Data Type Size SignINT
16 bits signed
DINT
32 bits signed
WORD
16 bits unsigned
DWORD
32 bits unsigned
REAL
32 bits signed
BOOL
1 bit n.d. BYTE
1 byte unsigned
CHAR
1 byte (only supported as char arrays using the String Java data type) n.d. The Driver automatically adapts the data type used by external applications and the S7 device depending on the value of the two configuration properties mentioned above.
The adaptation process involves the following steps:
Each device data type is internally converted by the driver from/to a Java type large enough to represent the value of the device data without losing precision. The type mappings are the following:
S7 Data Type Java TypeINT
int
DINT
int
WORD
int
DWORD
long
REAL
float
BOOL
boolean
BYTE
int
If the value type of the channel does not match the Java type specified in mapping above, a conversion is performed by the Driver to convert it to/from the matching type, choosing appropriately between the Number.toInt()
, Number.toLong()
, Number.toFloat()
or Number.toDouble()
methods. Precision losses may occur if the Java type used by the external application is not suitable to represent all possible values of the device data type.
The driver supports transferring data as raw byte arrays or ASCII strings:
BYTE_ARRAY
, the data.type configuration property must be set to BYTE
and the byte.count property must be set to the data length in bytes.STRING
, the data.type configuration property must be set to CHAR
and the array.data.length property must be set to the data length in bytes.The Driver supports setting the value of single bits without overwriting the other bits of the same byte. This operation can be performed defining a channel having BOOLEAN
as value type, BOOL
as s7.data.type and the proper index set to the bit.index property.
The Driver will fetch the byte containing the bit to be written, update its contents and then write back the obtained value. If multiple bits on the same byte need to be modified, the driver will perform only one read and write for that byte. If bits that need to be changed are located in contiguous bytes, the driver will perform only one bulk read and one bulk write transferring all the required data in a single request.
"},{"location":"connect-field-devices/sensehat-driver/","title":"RaspberryPi SenseHat driver","text":"The SenseHat driver allows to interact to a RaspberryPi SenseHat device using Kura Driver, Asset and Wires frameworks. The driver allows access to the following resources:
The driver-specific channel configuration contains a single parameter, resource, which allows to select the specific device resource that the channel is addressing (a sensor, a joystick event, etc).
Note about running on OpenJDK
If some exceptions reporting Locked by other application
are visible in the log and the driver fails to start, try switching to the Oracle JVM by installing the oracle-java8-jdk
package. For more information on the problem, please see this GitHub issue.
As the others Drivers supported by Kura, it is distributed as a deployment package on the Eclipse Marketplace here. It can be installed following the instructions provided here.
In order to use the driver, the Sensehat Support Library Bundle for Eclipse Kura needs to be installed as a prerequisite dependency. It is available from Eclipse Marketplace here.
"},{"location":"connect-field-devices/sensehat-driver/#sensors","title":"Sensors","text":"The following values of the resource parameters refer to device sensors:
Resource Unit Description ACCELERATION_X, ACCELERATION_Y, ACCELERATION_Z G The proper acceleration for each axis GYROSCOPE_X, GYROSCOPE_Y, GYROSCOPE_Z rad/S The angular acceleration for each axis MAGNETOMETER_X, MAGNETOMETER_Y, MAGNETOMETERE_Z uT The magnetometer value for each axis HUMIDITY %rH The relative humidity PRESSURE mbar The pressure value TEMPERATURE_FROM_HUMIDITY \u00b0C The temperature obtained from the humidity sensor TEMPERATURE_FROM_PRESSURE \u00b0C The temperature obtained from the pressure sensorThe channels referencing sensor resources can only be used for reads and only in polling mode. The driver will attempt to convert the value obtained from the sensor into the data type selected using the value.type parameter
Example sensors Asset configuration:
"},{"location":"connect-field-devices/sensehat-driver/#joystick","title":"Joystick","text":"The SenseHat joystick provides four buttons:
For each button, the driver allows to listen to the following events:
The values of the resource parameter related to joystick have the following structure:
JOYSTICK_{BUTTON}_{EVENT}
Channels referencing joystick events must use LONG as value.type. The channel value supplied by the driver is the Java timestamp in milliseconds of the Joystick event, a value of 0 signifies that no events have been observed yet.
Joystick related channels can be only used for reading and both in polling and event-driven mode.
Example joystick Asset configuration:
"},{"location":"connect-field-devices/sensehat-driver/#led-matrix","title":"LED Matrix","text":"The driver allows accessing the SenseHat LED matrix in two ways:
The coordinate system used by the driver defines the x
coordinate as increasing along the direction identified by the joystick RIGHT button and the y
coordinate increasing along the direction identified by the DOWN joystick button.
In monochrome mode, only two colors will be used: the front color and the back color.
"},{"location":"connect-field-devices/sensehat-driver/#front-and-back-colors","title":"Front and back colors","text":"Front and back colors can be configured using channels having the following values for the resource parameter:
These channel types allow to set the rgb components of the front and back color and can only be used in write mode. The supplied value must be a floating point number between 0 (led turned off) and 1 (full brightness). Note: Front and back colors are internally represented using the RGB565 format. The available colors are only the ones that can be represented using RGB565 and are supported by the device. Front and back color are retained for successive draw operations, the initial value for both colors is black (led turned off).
"},{"location":"connect-field-devices/sensehat-driver/#drawing","title":"Drawing","text":"The following resources can be used for modifying framebuffer contents:
LED_MATRIX_FB_MONOCHROME:
A channel of this type allows to set the framebuffer contents in monochrome mode. It can only be used in write mode and its value.type must be BYTE_ARRAY.
The supplied value must be a byte array of length 64 that represent the state of the 8x8 led matrix. The offset in the array of a pixel having coordinates (x, y)
is y*8 + x
. The back/front color will be used for a pixel if the corresponding byte in the array is zero/non-zero.
LED_MATRIX_CHARS:
A channel of this type allows showing a text message using the LED matrix. It can only be used for writing and its value.type must be STRING. The characters of the message will be rendered using the front color and the background using the back color.
The following resource allows writing the framebuffer using the RGB565 format:
LED_MATRIX_FB_RGB565:
A channel of this type allows to set the framebuffer contents in RGB565 mode. It can only be used in write mode and its value.type must be BYTE_ARRAY.
The supplied value must be a byte array of length 128 that represents the state of the 8x8 led matrix. Each pixel is represented by two consecutive bytes in the following way:
| MSB | LSB |\n| RRRRRGGG | GGGBBBBB |\n| 15 ... 8 | 7 ... 0 |\n
The LSB must be stored first in the array, the offset of the LSB and MSB for a pixel at coordinates (x, y)
is the following:
2*(y*8 + x)
2*(y*8 + x) + 1
LED_MATRIX_CLEAR:
Writing anything to a LED_MATRIX_CLEAR channel will clear the framebuffer turning off all leds.
LED_MATRIX_ROTATION:
Allows to rotate the framebuffer of 0, 90, 180, and 170 degrees clockwise. Rotation setting will be retained for successive draw operations. The default value is 0. Writes to a LED_MATRIX_ROTATION channel can be performed using any numeric type as value.type.
Example framebuffer Asset configuration:
"},{"location":"connect-field-devices/sensehat-driver/#examples","title":"Examples","text":"This section contains some examples describing how to use the driver using Kura Wires and the Wires Script filter.
"},{"location":"connect-field-devices/sensehat-driver/#moving-a-pixel-using-the-joystick","title":"Moving a pixel using the Joystick","text":"var FB_SIZE = 8\n\nif (typeof(state) === 'undefined') {\n // framebuffer as byte array (0 -> back color, non zero -> front color)\n var fb = newByteArray(FB_SIZE*FB_SIZE|0)\n // record to be emitted for updating the fb\n var outRecord = newWireRecord()\n // property in emitted record containing fb data\n // change the name if needed\n // should match the name of a channel configured as LED_MATRIX_FB_MONOCHROME\n outRecord['fb_mono'] = newByteArrayValue(fb)\n\n state = {\n fb: fb,\n outRecord: outRecord,\n x: 0, // current pixel position\n y: 0,\n dx: 0, // deltas to be added to pixel position\n dy: 0,\n }\n}\n\nif (typeof(actions) === 'undefined') {\n // associations between input property names\n // and position update actions,\n // input can be supplied using an Asset\n // with joystick event channels\n actions = {\n 'up_release' : function () {\n // decrease y coordinate\n state.dy = -1\n },\n 'down_release' : function () {\n // increase y coordinate\n state.dy = 1\n },\n 'left_release' : function () {\n // decrease x coordinate\n state.dx = -1\n },\n 'right_release' : function () {\n // increase x coordinate\n state.dx = 1\n }\n }\n}\n\nif (input.records.length) {\n var input = input.records[0]\n var update = false\n\n for (var prop in input) {\n var action = actions[prop]\n // if there is an action associated with the received property, execute it\n if (action) {\n action()\n // request framebuffer update\n update = true\n }\n }\n\n if (update) {\n // framebuffer update requested\n // clear old pixel\n state.fb[state.y*FB_SIZE + state.x] = 0\n // compute new pixel position\n state.x = (state.x + state.dx + FB_SIZE) % FB_SIZE\n state.y = (state.y + state.dy + FB_SIZE) % FB_SIZE\n // set new pixel\n state.fb[state.y*FB_SIZE + state.x] = 1\n // clear deltas\n state.dx=0\n state.dy=0\n // emit record\n output.add(state.outRecord)\n }\n}\n
"},{"location":"connect-field-devices/sensehat-driver/#using-rgb565-framebuffer","title":"Using RGB565 framebuffer","text":"var FB_SIZE = 8\nvar BYTES_PER_PIXEL = 2\n\nif (typeof(state) === 'undefined') {\n // framebuffer as RGB565 byte array\n var fb = newByteArray(FB_SIZE * FB_SIZE * BYTES_PER_PIXEL | 0)\n // record to be emitted for updating the fb\n var outRecord = newWireRecord()\n // property in emitted record containing fb data\n // change the name if needed\n // must match the name of a channel configured as LED_MATRIX_FB_565\n outRecord['fb_rgb565'] = newByteArrayValue(fb)\n\n // framebuffer array and output record\n state = {\n fb: fb,\n outRecord: outRecord,\n }\n\n RMASK = ((1 << 5) - 1)\n GMASK = ((1 << 6) - 1)\n BMASK = RMASK\n\n // converts the r, g, b values provided as a floating point\n // number between 0 and 1 to RGB565 and stores the result\n // inside the output array\n function putPixel(off, r, g, b) {\n var _r = Math.floor(r * RMASK) & 0xff\n var _g = Math.floor(g * GMASK) & 0xff\n var _b = Math.floor(b * BMASK) & 0xff\n\n var b0 = (_r << 3 | _g >> 3)\n var b1 = (_g << 5 | _b)\n\n state.fb[off + 1] = b0\n state.fb[off] = b1\n }\n\n // parameters for 3 sin waves, one per color component\n RED_WAVE_PARAMS = {\n a: 5,\n b: 10,\n c: 10,\n d: 0\n }\n\n GREEN_WAVE_PARAMS = {\n a: 5,\n b: 10,\n c: 10,\n d: 1\n }\n\n BLUE_WAVE_PARAMS = {\n a: 5,\n b: 10,\n c: 10,\n d: 2\n }\n\n function wave(x, y, t, params) {\n return Math.abs(Math.sin(2*Math.PI*(t + x/params.b + y/params.c + params.d)/params.a))\n }\n}\n\nvar t = new Date().getTime() / 1000\n\nvar off = 0\nfor (var y = 0; y < FB_SIZE; y++)\n for (var x = 0; x < FB_SIZE; x++) {\n var r = wave(x, y, t, RED_WAVE_PARAMS)\n var g = wave(x, y, t, GREEN_WAVE_PARAMS)\n var b = wave(x, y, t, BLUE_WAVE_PARAMS)\n putPixel(off, r, g, b)\n off += 2\n }\n\noutput.add(state.outRecord)\n
"},{"location":"connect-field-devices/sensortag-driver/","title":"TI SensorTag Driver","text":"Eclipse Kura provides a specific driver that can be used to interact with Texas Instruments SensorTag devices. The driver is available only for gateways that support the new Bluetooth LE APIs. It can be used in the Wires framework, the Asset model or directly using the Driver itself.
Warning
The SensorTag driver can be used only with TI SensorTags with firmware version >1.20. If your device has an older firmware, please update it.
"},{"location":"connect-field-devices/sensortag-driver/#features","title":"Features","text":"The SensorTag Driver can be used to get the values from all the sensor installed on the tag (both in polling mode and notification):
Moreover, the following resources can be written by the driver: - read and green leds - buzzer
When a notification is enabled for a specific channel (sensor), the notification period can be set.
"},{"location":"connect-field-devices/sensortag-driver/#installation","title":"Installation","text":"As the other Drivers supported by Kura, it is distributed as a deployment package on the Eclipse Marketplace here and here. It can be installed following the instructions provided here.
"},{"location":"connect-field-devices/sensortag-driver/#instance-creation","title":"Instance creation","text":"A new TiSensorTag Driver instance can be created either by clicking the New Driver button in the dedicated Drivers and Assets Web UI section or by clicking on the + button under Services. In both cases, the org.eclipse.kura.driver.ble.sensortag
factory must be selected and a unique name must be provided for the new instance. Once instantiated, the SensorTag Driver has to be configured setting the Bluetooth interface name (i.e. hci0) that will be used to connect to the device.
The SensorTag Driver channel can be configured with the following parameters:
READ
, WRITE
, or READ_WRITE
).Eclipse Kura provides a specific driver that can be used to interact with Bosch Xdk110 devices. The driver is available only for gateways that support the new Bluetooth LE APIs. It can be used in to the Wires framework, the Asset model or directly using the Driver itself.
Info
The Xdk driver can only be used with Xdk110 with VirtualXdkDemo installed and with firmware version > 3.5.0. If your device has an older firmware, please update it.
"},{"location":"connect-field-devices/xdk-driver/#features","title":"Features","text":"The Xdk Driver can be used to get the values from all the sensor provider by the xdk110 (both in polling mode and notification):
G
The proper acceleration for each axis* GYROSCOPE_X, GYROSCOPE_Y, GYROSCOPE_Z rad/S
The angular acceleration for each axis* LIGHT lux
The light value NOISE DpSpl
The acustic pressure value PRESSURE Pa
The pressure value TEMPERATURE C
The temperature value HUMIDITY %rH
The relative humidity SD_CARD_DETECTION_STATUS boolean
SD-Card detect status PUSH_BUTTONS bit
Button status, encoded as bit field: Bit 0, Button 1; Bit 1, Button 2 MAGNETOMETER_X, MAGNETOMETER_Y, MAGNETOMETERE_Z uT
The magnetometer value for each axis MAGNETOMETER_RESISTENCE ohm
The magnetometer resistence value LED_STATUS bit
Led status, encoded as a bit field: Bit 0: yellow Led; Bit 1: orange Led; Bit 2: red Led VOLTAGE_LEM mV
RMS voltage of LEM sensor *If the Quaternion rappresentation is selected, then:
Resource Unit Description QUATERNION_M, QUATERNION_X, QUATERNION_Y, QUATERNION_Znumber
The rotation-quaternion for each axis When a notification is enabled for a specific channel (sensor), the notification period can't be set. Use the Timer in Wire Graph to set polling.
"},{"location":"connect-field-devices/xdk-driver/#documentation","title":"Documentation","text":"All the information regarding the Xdk110 is available in the Xdk Bosch Connectivity here website. The XDK-Workbench is the tool that can be used to develop software for the Xdk110. It can be downloaded from here. XDK-Workbench is required to install VirtualXdkDemo.
Warning
We found connection problems with Xdk, probably due to issues with XDK-Workbench version 3.6.0. We recommend installing version 3.5.0.
The Virtual XDK application user guide contains all the information regarding the XDK110 UUIDs and data formats here.
Info
To switch between quaternion and sensor representation, the XDK110 needs to be instructed using the 55b741d5-7ada-11e4-82f8-0800200c9a66
UUID. Set it to 0x01
to enable Quaternions.
If quaternion representation is enabled, the data format is as follows:
Bytes Data Type 0,1,2 & 3 Rotation Quaternion M float 4,5,6 & 7 Rotation Quaternion X float 8,9,10 & 11 Rotation Quaternion Y float 12,13,14 & 15 Rotation Quaternion Z float"},{"location":"connect-field-devices/xdk-driver/#installation","title":"Installation","text":"As the others Drivers supported by Kura, it is distributed as a deployment package on the Eclipse Marketplace here. It can be installed following the instructions provided here.
"},{"location":"connect-field-devices/xdk-driver/#instance-creation","title":"Instance creation","text":"A new Xdk Driver instance can be created either by clicking the New Driver button in the dedicated Drivers and Assets Web UI section or by clicking on the +
button under Services. In both cases, the org.eclipse.kura.driver.ble.xdk
factory must be selected and a unique name must be provided for the new instance. Once instantiated, the Xdk Driver has to be configured setting the Bluetooth interface name (i.e. hci0
). Other options available are related to the quaternion/sensor representation and the sensor sampling rate (in Hz).
The Xdk Driver channel can be configured with the following parameters:
type: the channel type, (READ
, WRITE
, or READ_WRITE
).
Warning
The Xdk driver can only be used with READ.
value.type: the Java type of the channel value. The value read by the Driver will be converted to the value.type.
Apart from using the simple ActiveMQ-7 MQTT instance available in the Simple Artemis MQTT Broker Service, this service allows to configure, in a more detailed way, the characteristics of the ActiveMQ-7 broker instance running in Kura.
This service exposes the following configuration parameters:
Please refer to the official documentation for more details on how to configure the ActiveMQ broker service.
"},{"location":"core-services/active-mq-artemis-broker/#service-usage-example","title":"Service Usage Example","text":"Setting the Broker XML field as follows:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<configuration xmlns=\"urn:activemq\"\nxmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\nxsi:schemaLocation=\"\nurn:activemq https://raw.githubusercontent.com/apache/activemq-artemis/master/artemis-server/src/main/resources/schema/artemis-server.xsd\nurn:activemq:core https://raw.githubusercontent.com/apache/activemq-artemis/master/artemis-server/src/main/resources/schema/artemis-configuration.xsd\nurn:activemq:jms https://raw.githubusercontent.com/apache/activemq-artemis/master/artemis-jms-server/src/main/resources/schema/artemis-jms.xsd\n\">\n\n <core xmlns=\"urn:activemq:core\">\n <persistence-enabled>false</persistence-enabled>\n\n <acceptors>\n <acceptor name=\"netty-acceptor\">tcp://localhost:61616</acceptor>\n <acceptor name=\"amqp-acceptor\">tcp://localhost:5672?protocols=AMQP</acceptor>\n <acceptor name=\"mqtt-acceptor\">tcp://localhost:1883?protocols=MQTT</acceptor>\n </acceptors>\n\n <resolve-protocols>false</resolve-protocols>\n\n <security-settings>\n <!-- WARNING: this is only for testing and completely insecure -->\n <security-setting match=\"#\">\n <permission type=\"createDurableQueue\" roles=\"guest\"/>\n <permission type=\"deleteDurableQueue\" roles=\"guest\"/>\n <permission type=\"createNonDurableQueue\" roles=\"guest\"/>\n <permission type=\"deleteNonDurableQueue\" roles=\"guest\"/>\n <permission type=\"consume\" roles=\"guest\"/>\n <permission type=\"send\" roles=\"guest\"/>\n </security-setting>\n </security-settings>\n\n </core>\n\n <jms xmlns=\"urn:activemq:jms\">\n <topic name=\"TEST.T.1\" />\n </jms>\n\n</configuration>\n
the User configuration to:
guest=test12|guest\n
while setting the Default user name to:
guest\n
will determine that the TCP ports 1883, 5672 and 61616 are now open (you can verify that via netstat -antup).
Configuring the MqttDataTransport in System -> Cloud Services -> MqttDataTransport to use:
Clicking on the Connect button will result in a successful connection of Kura cloud service to the ActiveMQ-7 MQTT broker.
Note
The XML configuration above only allows connections originating from the gateway itself. In order to allow external connection the bind URLs specified using the acceptor
tag must be modified by specifying an external accessible address instead of localhost
. If the bind address is set to 0.0.0.0
, the broker will listen on all available addresses.
The ClockService handles the date and time management of the system. If enabled, it tries to update the system date and time using a Network Time Protocol (NTP) server. NTP can use NTS as authentication mechanism through chrony.
"},{"location":"core-services/clock-service/#service-configuration","title":"Service Configuration","text":"To manage the system date and time, select the ClockService option located in the Services area as shown in the screen capture below.
The ClockService provides the following configuration parameters:
enabled: sets whether or not this service is enabled or disabled (Required field).
clock.set.hwclock: defines if the hardware clock of the gateway must be synced after the system time is set. If enabled, the service calls the Linux command hwclock --utc --systohc
.
clock.provider: specifies one among Java NTP client (java-ntp), Linux chrony command (chrony-advanced), Linux ntpdate command (ntpd) (Required field). If chrony-advanced is used, Kura will not change system and/or hardware clock directly, delegating these operations to chrony.
clock.ntp.host: sets a valid NTP server host address.
clock.ntp.port: sets a valid NTP port number (not supported by ntpd, use the port 123 in that case).
clock.ntp.timeout: specifies the NTP timeout in milliseconds.
clock.ntp.max-retry: defines the number of retries when a sync fails (retry at every minute). Subsequently, the next retry occurs on the next refresh interval.
clock.ntp.retry.interval: defines the interval in seconds between each retry when a sync fails. If the clock.ntp.refresh-interval parameter is less than zero, there is no update. If the clock.ntp.refresh-interval parameter is equal to zero, there is only one try at startup (Required field).
clock.ntp.refresh-interval: defines the frequency (in seconds) at which the service tries to sync the clock. Note that at the start of Kura, when the ClockService is enabled, it tries to sync the clock every minute until it is successful. After a successful sync, this operation is performed at the frequency defined by this parameter. If the value is less than zero, there is no update. If the value is equal to zero, syncs only once at startup.
chrony.advanced.config: specifies the content of the chrony configuration file. If this field is left blank, the default system configuration will be used. All fields above will be ignored. To obtain the hardware clock synchronization the directive rtcsync could be used. The rtcsync directive provides the hardware clock synchronization made by the linux kernel every 11 minutes. For further information reference the chrony website.
Two example configuration are shown below.
"},{"location":"core-services/clock-service/#nts-secure-configuration-example","title":"NTS Secure configuration example","text":"server time.cloudflare.com iburst nts\nserver nts.sth1.ntp.se iburst nts\nserver nts.sth2.ntp.se iburst nts\n\nsourcedir /etc/chrony/sources.d\n\ndriftfile /var/lib/chrony/chrony.drift\n\nlogdir /var/log/chrony\n\nmaxupdateskew 100.0\n\nrtcsync\n\nmakestep 1 -1\n\nleapsectz right/UTC\n
Note
If the system stays disconnected from the network for a long time or if the backup battery is not working properly or is depleted, there is the possibility of a synchronization failure due to the client inability to verify the server certificates.
If this happens and no counter action has been taken in the chrony configuration file, the risk is that the gateway will be unable to synchronise again its date and therefore will not be able to connect to the cloud and/or be fully operational.
A possible way to prevent this issue is to temporary disable the certificate verification using the directive nocerttimecheck. This directory will disable the security checks of the activation and expiration times of certificates for the specified number of clock updates and should be used with caution due to the important security implications.
As reported by the official Chrony documentation, disabling the time checks has important security implications and should be used only as a last resort, preferably with a minimal number of trusted certificates. The default value is 0, which means the time checks are always enabled.
An example of the directive is nocerttimecheck 1
This would disable the time checks until the clock is updated for the first time, assuming the first update corrects the clock and later checks can work with correct time.
# Use public NTP servers from the pool.ntp.org project.\npool pool.ntp.org iburst\n\n# Record the rate at which the system clock gains/losses time.\ndriftfile /var/lib/chrony/drift\n\n# Allow the system clock to be stepped in the first three updates\n# if its offset is larger than 1 second.\nmakestep 1 -1\n\n# Enable kernel synchronization of the real-time clock (RTC).\nrtcsync\n
"},{"location":"core-services/command-service/","title":"Command Service","text":"The Command Service provides methods for running system commands from the Kura web console or from Kapua. In the Kura web console, the service is available clicking on the Command tab under the Device section, while for the cloud platform please refer to the official documentation.
To run a command simply fill the Execute field with the command and click the Execute button. The service also provides the ability for a script to execute using the File option of the Command tab in the Kura web console or the Kapua Cloud Console. This script must be compressed into a zip file with the eventual, associated resource files.
Once the file is selected and Execute is clicked, the zip file is sent embedded in an MQTT message on the device. The Command Service in the device stores the file in /tmp, unzips it, and tries to execute a shell script if one is present in the file. Note that in this case, the Execute parameter cannot be empty; a simple command, such as ls -l /tmp
, may be entered.
Warning
When decompressed, the script loses its executable attribute. To fix this problem, if you plan to execute a script, the command entered into the Execute line must trigger the execution: ** bash [name of the script] **.
The configuration of the service is in the CommandService tab located in the Services area as shown in the screen capture below.
The Command Service provides the following configuration parameters:
Command Enable: sets whether this service is enabled or disabled in the cloud platform (Required field).
Command Password Value: sets a password to protect this service.
Command Working Directory: specifies the working directory where the command execution is performed.
Command Timeout: sets the timeout (in seconds) for the command execution.
Command Environment: supplies a space-separated list of environment variables in the format key=value.
Privileged/Unprivileged Command Service Selection: sets the modality of the command service. When set to privileged, the commands are run using the (privileged) user that started Kura, tipically kurad or root. When set to unprivileged, a standard user will run the commands.
When a command execution is requested in the cloud platform, it sends an MQTT control message to the device requesting that the command be executed. On the device, the Command Service opens a temporary shell in the command.working.directory, sets the command.environment variables (if any), and waits command.timeout seconds to get command response.
"},{"location":"core-services/configuration-service/","title":"Configuration Service","text":"The Configuration Service is responsible to manage the framework configuration by creating and persisting the framework snapshot. Built on top of the OSGi Configuration Admin and Metatype services, it is also responsible to track and manage the creation and deletion of service instances as well as OSGi component factories.
The ConfigurationService is accessible using the following REST APIs and cloud request handlers:
Containerized applications are becoming increasingly popular in the software ecosystem as a way to deploy and distribute applications. As a result, ensuring the security of software supply chains has become a critical concern. Implementing best practices, such as signing and verifying images to mitigate man-in-the-middle (MITM) attacks and validating their authenticity and freshness, play a pivotal role in safeguarding the integrity of the software supply chain.
To ensure the authenticity and integrity of the code within the container images, binding the image to a specific entity or organization via signature verification is crucial and increasingly common.
The purpose of this document is to provide a high-level understanding of the Eclipse Kura container authenticity and allowlist enforcement feature introduced with Eclipse Kura version 5.5.0.
"},{"location":"core-services/container-orchestration-image-auth/#high-level-flow","title":"High-level flow","text":"The Eclipse Kura container authenticity and allowlist enforcement feature is designed to address container authenticity concerns by providing a mechanism to perform the signature verification of container images and restricting which container images can be deployed on the Eclipse Kura instance.
This is achieved by implementing the following flow:
Description of the flow:
This flow applies to both containers managed by Eclipse Kura itself and containers ran directly by the user via CLI, allowing for a fine-grained control over the container images that can be deployed on the Eclipse Kura instance.
Note that the user can still directly provide an image digest when running an Eclipse Kura-managed container. This will prevent the Eclipse Kura automatic signature verification process to run. This feature is meant to be used when:
Regarding the containers not managed by Eclipse Kura, the Container Orchestration service provides a security feature which enforces the containers allowed to run on the system. This feature can be enabled or disabled through the Allowlist Enforcement Enabled
option.
This mechanism leverages the concept of digest, which is a unique and immutable identifier for a container image: it is therefore an excellent mean to identify the image from which a container was created.
Given the above, Eclipse Kura allows the user to provide a list of container image digests in the Container Image Allowlist
field, in the form of newline-separated strings: when a container is started on the host system (whether it is launched by Eclipse Kura or by a terminal CLI), Eclipse Kura retrieves the image from which the container was created, extracts the digest and verifies that it is present in the allowlist provided during service configuration.
If the image digest is present and matches the container's one, it is then allowed to run without interference. Otherwise, it is immediately stopped and deleted from the host system.
A similar behaviour is performed at Eclipse Kura startup or when the enforcement is enabled at runtime: if there are already containers on the device (whether they are started or stopped) and the enforcement is activated, Eclipse Kura extracts the digests from the containers and compares them with those in the allowlist. Containers that have been created from images whose digests are in the allowlist will be left running, otherwise they will be stopped and deleted from the descriptors list.
The verification is performed by intersecting the list of digests extracted by the containers and the one provided in the configuration: in this way, an empty intersection will result in a failing verification, while a non-empty one means that the image digests is equal to one of the allowlist entries.
"},{"location":"core-services/container-orchestration-image-auth/#example-scenarios","title":"Example scenarios","text":"A user wants to leverage the container enforcement in order to let only docker containers started from an image named foo_image
to be run on the device. To do this, they should enable the Container Enforcement by setting the Allowlist Enforcement Enabled
to true
, and fill the Container Image Allowlist
field with the digest of the foo_image
docker image (i.e.sha256:0000000000000000000000000000000000000000000000000000000000000000
in the example below).
Let's suppose that on the device there are already two containers running, one created from the foo_image
an one from an image named unwanted_image
with digest sha256:9999999999999999999999999999999999999999999999999999999999999999
. Once the enforcement starts with the configuration previously described, it extracts the digests of both containers and checks if they're included in the provided allowlist: in this case, the container originating from the foo_image
will be allowed to run, while the one created from the unwanted_image
will be stopped and deleted, because its digest is not included in the allowlist.
The same happens also for already stopped containers: if the digests is verified, they'll be left in the descriptors list in the Stopped state, otherwise they'll be deleted.
"},{"location":"core-services/container-orchestration-image-auth/#running-container-after-enforcement-feature-startup","title":"Running Container After Enforcement Feature Startup","text":"After the starting phase just described, Eclipse Kura will continuously monitor the activity of the docker engine. Whenever a container is started on the device, it will check the image digest from which the container was created, comparing it to the ones inside the allowlist: if the container is created from the foo_image
docker image, it will be allowed to start, otherwise it will be stopped and deleted. If the user wants to add more than one allowed image, for example one named wanted_image
with digest sha256:1111111111111111111111111111111111111111111111111111111111111111
), it just needs to add it to the newline-separated list.
As explained in the previous section, Managed Containers (i.e. org.eclipse.kura.container.provider.ContainerInstance
s) support Container Signature validation. To do so a new API has been introduced: the ContainerSignatureValidationService
.
Currently, there are three main mechanism for container signature verification:
This newly introduced service allows Eclipse Kura to have multiple different Services implementing this interface and, thus, support all major signature mechanisms. A reference implementation for the ContainerSignatureValidationService
is the DummyContainerSignatureValidationService
available in Kura examples
folder for anyone wanting to implement an alternative ContainerSignatureValidationService
.
When a ContainerSignatureValidationService
is installed on Eclipse Kura, it gets automatically registered among the available validators and will be used to perform the signature validation. Under the hood, the ContainerInstance
has a list of the available ContainerSignatureValidationService
providers that, upon receiving a configuration update, it interrogates to check whether the requested container image is authentic using the provided Trust Anchor.
This means that Eclipse Kura doesn't need to prompt the user for selecting the correct ContainerSignatureValidationService
when performing the check.
Once the image signature is validated, the image digest is stored in the Eclipse Kura snapshot and added to the ContainerOrchestratorService
allowlist (see section above). A container whose image digest is available in the allowlist won't be validated again, therefore after the initial check, the internet connection is no longer required for it to work.
Let's suppose to have a device on which Eclipse Eclipse Kura is running with the Container Orchestration Service enabled, its Enforcement feature disabled and a Container Instance named test-container
up and running on the system.
A user wants to activate the Enforcement feature, so it enables the Allowlist Enforcement Enabled
option in the Container Orchestration Service, but leaves the Container Image Allowlist
option blank because it wants that no containers are started outside the framework.
As the feature starts, it checks all the container running on the device, including the test-container
, which will be stopped and deleted: this happens because the container digest is not included in the Container Orchestration Service Allowlist and the Container Instance is not providing any information through its Container Image Enforcement Digest
option.
In order to allow the Container Instance, the user should provide the correct digest in the instance settings. Let's suppose that the digest of the image from which the container is created is sha256:0000000000000000000000000000000000000000000000000000000000000000
and that the user fills the corresponding option with it: once the Container Instance is updated, the provided digest is included in the Enforcement feature allowlist, so the container will be allowed to run without interference. This case can be summarised as:
Once the instance digest is added to the enforcement feature, it can be used also to authorise container run by the Command Line Interface, or other instances on Eclipse Eclipse Eclipse Kura without providing the digest option. But what happen if the Container Instance is disabled? The aim of the Container Instance Enforcement Digest is to be used as an authorization method of the instance itself: this means that its digest is added to the enforcement feature allowlist only if the instance is enabled.
As it can be seen from the image, the merged Enforcement Allowlist
box doesn't contain the digest associated to the Container Instance, because, being it disabled, the corresponding digest is ignored. If the enforcement is enabled and a container with digest DIGEST Z is started, it will then be stopped and deleted, because its digest won't be included in the allowlist.
Finally, everytime a Container Image Enforcement Digest option is modified, or the ContainerInstance is disabled or deleted, the enforcement feature will perform a check on all the already running containers. This is done because, if the digest that was previously provided has changed after an instance update, or removed due to disabling or deleting the instance, those containers that were previously authorised by this digest are no longer allowed to run. So they must be stopped and deleted.
Warning
The digests provided through Container Instances allow running also container started by the CommandLineInterface or by other Container Instances in the framework, even without providing the digest.
It has to be considered that, if the ContainerInstance is disabled (or its digest option changes), the enforcement feature will stop and delete the containers that are no longer matching the provided digest.
The user needs to be careful, then, to rely only on the digests set in the ContainerInstances options. If the user will need to run containers from the CLI, it is preferable to use the allowlist of the Container Orchestration Service. For the Container Instances, is a good practise to provide a digest.
"},{"location":"core-services/container-orchestration-image-auth/#container-signature-verification","title":"Container Signature Verification","text":"If the Container Image Enforcement Digest option is not provided, Eclipse Eclipse Kura will proceed with the Signature Verification: this process tries to extract the digest of the image from which the container was started.
Let's then suppose that we are back at the beginning of the previous example, with a blank Container Orchestration Service allowlist and a not given Container Instance Digest, but this time a Trust Anchor option is given: in this case Eclipse Eclipse Kura will start the Signature Verification Process, in order to extract the digest.
If, for whatever reason, the Signature Verification fails, no digests will be added to the allowlist: if the enforcement feature is enabled, the started container will be then stopped and deleted by the Enforcement Monitor, because no digests are included in the final Enforcement Allowlist.
While, if the procedure completes correctly, the extracted digest will be added to the Enforcement Allowlist and written in the snapshot: in this way the container will pass the enforcement feature check, and the obtained digest will be stored as part of the Container Instance's configuration just started.
If the user wants to check again the digest through the Signature Verification Service, it just needs to erase the Container Image Enforcement Digest option from the configuration of the Container Instance: in this way the Signature feature will be triggered again and the digest recalculated.
Warning
Even in this situation, the digest could be used to authenticate container started from the CommandLineInterface: also in this case keep in mind that if the Container Instance is disabled, stopped or updated with different digest, those CLI-based container could be stopped and deleted.
"},{"location":"core-services/container-orchestration-provider-apis/","title":"Container Orchestration Provider APIs","text":""},{"location":"core-services/container-orchestration-provider-apis/#java-api","title":"Java API","text":""},{"location":"core-services/container-orchestration-provider-apis/#containerorchestrationservice","title":"ContainerOrchestrationService","text":"The ContainerOrchestrationService is used to directly communicate with the running container engine. It exposes methods for listing, creating, and stopping containers. This class utilizes an instantiated ContainerConfiguration object as a parameter for container creation.
"},{"location":"core-services/container-orchestration-provider-apis/#containerconfiguration","title":"ContainerConfiguration","text":"The ContainerConfiguration class, allows you to define a container to create. Using the embedded builder class, one can define many container-related parameters such as name, image, ports and volume mounts.
"},{"location":"core-services/container-orchestration-provider-apis/#containerinstancedescriptor","title":"ContainerInstanceDescriptor","text":"The ContainerInstanceDescriptor class is used to describe a container that has already been created. This class contains runtime information such as the ID of the container.
"},{"location":"core-services/container-orchestration-provider-apis/#containerstate","title":"ContainerState","text":"The ContainerState is a class that exposes an enum of container states tracked by the framework.
"},{"location":"core-services/container-orchestration-provider-apis/#passwordregistrycredentials","title":"PasswordRegistryCredentials","text":"The PasswordRegistryCredentials class stores password credentials when provisioning a container to pull from an alternative password-protected registry.
"},{"location":"core-services/container-orchestration-provider-apis/#passwordregistrycredentials_1","title":"PasswordRegistryCredentials","text":"The PasswordRegistryCredentials class stores password credentials when provisioning a container to pull from an alternative password-protected registry.
Note
The Container Orchestration Provider exports an MQTT-Namespace API. This API can be used to manage containers via MQTT requests from external applications. Please visit the Remote Gateway Inventory via MQTT documentation for more information.
"},{"location":"core-services/container-orchestration-provider-authenticated-registries/","title":"Container Orchestration Provider Authenticated Registries","text":"The Container Orchestrator provider allows the user to pull images from private and password-protected registries. The following document will provide examples of how to connect to some popular registries.
Note
These guides make the following two assumptions.
**Image Name: ** <Docker-Hub username>/<image name>
for exampleeclipse/kura
.
Populate the credential fields:
Sign in to your amazon web console, navigate to ECR and identify which container you will like to pull onto the gateway. Copy the URI of the container. This URI will reveal the information required for the following steps. Here is how to decode the URI <identifier>.dkr.ecr.<ecr-region>.amazonaws.com/<directory>/<image name>:<image tag>
.
Generating an AWS-ECR access password. Open a terminal window on the machine with aws-cli installed and enter the following command aws ecr get-login-password --region <ecr-region>
. Your ECR region can be found by inspecting the container URI string copied in the previous step. This command will return a long string which will be used as the repo password in the gateway.
Populating information on the gateway.
<identifier>.dkr.ecr.<ecr-region>.amazonaws.com/<directory>/<image name>
<image tag>
<identifier>.dkr.ecr.<ecr-region>.amazonaws.com/<directory>/
AWS
A fully configured container set to pull AWS will look like the following.
"},{"location":"core-services/container-orchestration-provider-usage/","title":"Container Orchestration Provider Usage","text":""},{"location":"core-services/container-orchestration-provider-usage/#before-starting","title":"Before Starting","text":"For this bundle to function appropriately, the gateway must have a supported container engine installed and running. Currently, the only officially supported engine is Docker.
"},{"location":"core-services/container-orchestration-provider-usage/#starting-the-service","title":"Starting the Service","text":"To use this service select the ContainerOrchestrationService option located in the Services area. The ContainerOrchestrationService provides the following parameters:
To create a container, select the +
icon (Create a new component) under services. A popup dialogue box will appear. In the field Factory select org.eclipse.kura.container.provider.ContainerInstance from the drop-down. Then, use the Name field to specify a name for the container.
Note
The name specified in the 'Name' field will also be the name of the container when it is spun up by the orchestrator.
After pressing submit, a new component will be added under the services tab, with the name that was selected in the dialogue. Select this component to finish configuring the container.
"},{"location":"core-services/container-orchestration-provider-usage/#configuring-the-container","title":"Configuring the container","text":"To begin configuring the container, look under Services and select the item which has the name set in the previous step. Containers may be configured using the following fields:
Enabled - When true, the service will create the defined container. When false the API will not create the container or will destroy the container if already running.
Image Name - Describes the image that will be used to create the container. Remember to ensure that the selected image supports the architecture of the host machine, or else the container will not be able to start.
Image Tag - Describes the version of the container image that will be used to create the container.
Trust Anchor - Trust anchor used to verify the container image Signature Verification
Verify in transparency log - Sets the transparency log verification, to be used when a container image signature has been uploaded to the transparency log.
Container Image Enforcement Digest - A string representing the digest for the image that will be allowed to run by this container instance (eg: sha256:0000000000000000000000000000000000000000000000000000000000000000
). It is used in the Container Enforcement service provided by the Container Orchestration Service.
Authentication Registry URL - URL for an alternative registry to pull images from. (If the field is left blank, credentials will be applied to Docker-Hub). Please see the Authenticated Registries document for more information about connecting to different popular registries.
Authentication Username - Describes the username to access the container registry entered above.
Password - Describes the password to access the alternative container registry.
Image Download Retries - Describes the number of retries the framework will attempt to pull the image before giving up.
Image Download Retry Interval - Describes the amount of time the framework will wait before attempting to pull the image again.
Image Download Timeout - Describes the amount of time the framework will let the image download before timeout.
Internal Ports - This field accepts a comma-separated list of ports that will be internally exposed on the spun-up container. In this field, you can also specify which protocol to run at the port by appending a port with a colon and typing in the name of the network protocol. Example: 80, 443:tcp, 8080:udp
.
External Ports - This field accepts a comma-separated list of ports that will be externally exposed on the host machine.
Privileged Mode - This flag if enabled will give the container root capabilities to all devices on the host system. Please be aware that setting this flag can be dangerous, and must only be used in exceptional situations.
Environment Variables (optional) - This field accepts a comma-separated list of environment variables, which will be set inside the container when spun up.
Entrypoint Override (optional) - This field accepts a comma-separated list which is used to override the command used to start a container. Example: ./test.sh,-v,-d,--human-readable
.
Memory (optional) - This field allows the configuration of the maximum amount of memory the container can use in bytes. The value is a positive integer, optionally followed by a suffix of b, k, m, g, to indicate bytes, kilobytes, megabytes, or gigabytes. The minimum and default values depends by the native container orchestrator. If left empty, the memory assigned to the container will be set to a default value.
CPUs (optional) - This value specifies how many CPUs a container can use. Decimal values are allowed, so if set to 1.5, the container will use at most one and a half cpu resource.
GPUs (optional) - This field configures how many Nvidia GPUs a container can use. Allowed values are all
or an integer number. If there's no Nvidia GPU installed, leave it empty. The Nvidia Container Toolkit must be installed on the system to correctly configure the service, otherwise the container will not start. If the Nvidia Container Runtime is used, leave the field empty.
Volume Mount (optional) - This field accepts a comma-separated list of system-to-container file mounts. This allows for the container to access files on the host machine.
Peripheral Device (optional) - This field accepts a comma-separated list of device paths. This parameter allows devices to be passed through from the host to the container.
Runtime (optional): Specifies the fully qualified name of an alternate OCI-compatible runtime, which is used to run commands specified by the 'run' instruction. Example: nvidia
corresponds to --runtime=nvidia
. Note: when using the Nvidia Container Runtime, leave the GPUs field empty. The GPUs available on the system will be accessible from the container by default.
Networking Mode (optional) - Use this field to specify what networking mode the container will use. Possible Drivers include: bridge, none, container:{container id}, host. Please note that this field is case-sensitive. This field can also be used to connect to any of the networks listed by the cli command docker network ls
.
Logger Type - This field provides a drop-down selection of supported container logging drivers.
Logger Parameters (optional) - This field accepts a comma-separated list of logging parameters. More information can be found in the container-engine logger documentation, for instance here.
Restart Container On Failure - A boolean that tells the container engine to automatically restart the container when it has failed or shut down.
After specifying container parameters, ensure to set Enabled to true and press Apply. The container engine will then pull the respective image, spin up and start the container. If the gateway or the framework is power cycled, and the container and Container Orchestration Service are set to enabled, the framework will automatically start the container again upon startup.
"},{"location":"core-services/container-orchestration-provider-usage/#stopping-the-container","title":"Stopping the container","text":"Warning
Stopping a container will delete it in an irreversible way. Please be sure to only use stateless containers and/or save their data in external volumes.
To stop the container without deleting the component, set the Enabled field to false, and then press Apply. This will delete the running container, but leave this component available for running the container again in the future. If you want to completely remove the container and component, press the Delete button to the top right of the screen, and press Yes on the confirmation dialogue.
"},{"location":"core-services/container-orchestration-provider-usage/#container-management-dashboard","title":"Container Management Dashboard","text":"The Container Orchestration service also provides the user with an intuitive container dashboard. This dashboard shows all containers running on a gateway, including containers created with the framework and those created manually through the command-line interface. To utilize this dashboard the org.eclipse.container.orchestration.provider
(ContainerOrchestrationService) must be enabled, and the dashboard can be opened by navigating to Device > Containers.
The Container Orchestration Provider allows Kura to manage Docker. With this tool, you can arbitrarily pull and deploy containerized software packages and run them on your gateway. This Service allows the user to create, configure, start, and stop containers all from the browser. The bundle will also restart containers if the gateway is restarted.
The feature is composed of two bundles, one that exposes APIs for container management and one that implements those APIs. This API is exposed so that you can leverage it to implement containerization in your own Kura plugins.
"},{"location":"core-services/deployment-service/","title":"Deployment Service","text":"The Deployment Service allows to download files to the gateway and to perform actions on them. In the configuration tab it is possible to specify which is the directory that has to be used to store the downloaded files and the list of actions declared as deployment hooks that will be invoked when a corresponding metric is received with the download request.
The configuration requires to specify two parameters:
<request_type>=<hook_pid>
, where <hook_pid>
is the Kura Service Pid of a DeploymentHook instance and <request_type>
is the value of the request.type metric received with the request.Kura can detect changes to the components and publish them using a selected Cloud Publisher. There are two main components that enable this:
org.eclipse.kura.configuration.change.manager
, andorg.eclipse.kura.event.publisher
The org.eclipse.kura.configuration.change.manager
is responsible for detecting changes to any of the configurations currently running on the system and to publish a notification to a user-defined cloud publisher. By default, the org.eclipse.kura.event.publisher
is used.
The configuration change manager allows to collection of the PIDs of the components that have changed in the system. The configurable properties of this component are:
The collected PIDs are sent to the Cloud Publisher as a KuraMessage
with a payload body in JSON format. The timestamp of the KuraMessage
is set to the last detected configuration change event. An example of message body is:
[\n {\n \u201cpid\u201d: \u201corg.eclipse.kura.clock.ClockService\u201d\n },\n {\n \u201cpid\u201d: \u201corg.eclipse.kura.log.filesystem.provider.FilesystemLogProvider\u201d\n }\n]\n
In the example above, a ClockService update triggered the delay timer, which was then reset by a configuration update on the FilesystemLogProvider. Afterward, no configuration updates reset the timer so the message containing the two PIDs was sent after expiration.
"},{"location":"core-services/device-configuration-changes/#event-publisher","title":"Event Publisher","text":"By default, the org.eclipse.kura.event.publisher
used by the configuration change manager does the actual publishing on a user-defined topic of the form:
$EVT/#account_id/#client_id/CONF/V1/CHANGE
This topic is adjusted for integration with EC, but the $EVT
and the CONF/V1/CHANGE
parts can be customized according to user needs by tweaking the Topic prefix and Topic properties.
The #account_id
and #client_id
fields are substituted at runtime with the account name and client ID at the Data Transport Service layer of the associated Cloud Connection.
The Qos, Retain, and Priority properties are the usual ones defined in the standard Cloud Publisher.
"},{"location":"core-services/h2db-service/","title":"H2Db Service","text":"Kura integrates a Java SQL database named H2. The main features of this SQL Database are:
Kura supports the following H2 database features:
Persistence modes: The H2 implementation currently supports in-memory and file-based database instances. See the Persistence Modes section for more details.
Multiple database instances: It is possible to create and configure multiple database instances from the Kura Administration UI, these instances can be selectively consumed by applications. A default database instance is created automatically.
TCP Server: The current implementation allows external processes to access the database instances managed by Kura using TCP. This enables the integration of external applications that can share data with Kura components using the database.
Web-based console: It is possible to start the H2 Web console directly from the Kura Administration UI. The console can be used to inspect the database contents and perform arbitrary queries for debug purposes.
Basic credential management: The current implementation allows to change the password of the admin DB user from the Kura Administration UI. This allows the access restriction to the existing database instances.
By default, the DataService in Kura uses the H2 database to persist the messages.
"},{"location":"core-services/h2db-service/#limitations","title":"Limitations","text":"Private in-memory instances: Only named in-memory instances are supported (e.g. jdbc:h2:mem:<dbname>
, where <dbname>
is not the empty string), private instances represented by the jdbc:h2:mem:
URL are currently not supported.
Remote connections: The current implementation only supports embedded database instances. Connecting to remote instances using the jdbc:h2:tcp:*
and jdbc:h2:ssl:*
connector URLs is not supported.
Note
The new DbWireRecordFilter
and DbWireRecordStore
Wire components have been added. These components provide the same functionalities offered by the old H2DbWireRecordFilter
and H2DbWireRecordStore
components, but they can be used for connectiong to a generic relational database (i.e. H2DB, MySQL or MariaDB). The legacy components will continue to be available in order to keep backward compatibility, but will be deprecated since Kura 5.2.0 and should not be used for new installations.
To create a new H2 database instance, use the following procedure:
org.eclipse.kura.core.db.H2DbService
from the Factory drop-down list, enter an arbitrary name for the new instance and click Apply. The H2DbService provides the following configuration parameters:
Warning
If the database is created in persisted mode, please make sure that the Linux user running Eclipse Kura has the permissions required to create the database file. If the permissions are not ok, Eclipse Kura may be able to create the database (by default it runs with the CAP_DAC_OVERRIDE capability) but it may not be able to perform the periodic defragmentation process, this may cause the database file size to grow expecially if the write rate is high.
Executing the following commands as root
can be useful to detect potential issues, replace database_parent_directory
with the parent directory of the database file and kura_linux_user
with the Linux user that is executing Eclipse Kura (e.g. kurad):
export TARGET=\"$(readlink -f database_parent_directory)\"\nexport KURA_USER=\"kura_linux_user\"\nsudo -u \"${KURA_USER}\" sh -c \"touch '${TARGET}/.testfile' && rm '${TARGET}/.testfile'\"\n
If command fails it may be necessary to change the database directory or adjust the permissions.
User: Specifies the user for the database connection. Furthermore
Password: Specifies the password. The default password is the empty string.
Checkpoint interval (seconds): H2DbService instances support running periodic checkpoints to ensure data consistency. This parameter specifies the interval in seconds between two successive checkpoints. This setting has no effect for in-memory database instances.
Defrag interval (minutes): H2DbService instances support running periodic defragmentation (compaction). This parameter specifies the interval in minutes between two successive checkpoints, set to zero to disable. This setting has no effect for in-memory database instances. Existing database connections will be closed during the defragmentation process and need to be reopened by the applications.
Connection pool max size: The H2DbService manages connections using a connection pool. This parameter defines the maximum number of connections for the pool
A database instance is identified by its Kura service PID. The PID for the default instance is org.eclipse.kura.db.H2DbService
while the PID for instances created using the Web UI is the string entered in the Name field at step 2 of the previous section.
The built-in components that use database functionalities allow to specify which instance to use in their configuration. These components are the DataService component of the cloud stack, the DbWireRecordFilter and DbWireRecordStore wire components. The configuration of each component contains a property that allows to specify the service PID of the desired instance.
"},{"location":"core-services/h2db-service/#usage-through-wires","title":"Usage through Wires","text":"It is possible to store and extract Wire Records into/from a H2 database instance using the Wire Record Store and Wire Record Query wire components.
When a Wire Record is received by a Wire Record Store attached to a H2 based database instance, the data will be stored in a table whose name is the current value of the Record Collection Name configuration parameter of the Wire Component.
Each property contained in a Wire Record will be appended to a column with the same name as the property key. A new column will be created if it doesn't already exists.
Note
Storing wire record properties with the FLOAT data type using the Wire Record Store is not recommended since the type information will be lost. Values inserted as FLOAT using the Wire Record Store will be retrieved as DOUBLE using the Wire Record Query component.
Warning
It is not recommended to store Wire Records having properties with the same key and different value type. If the value type changes, the target column will be dropped and recreated with the type derived from the last received record. All existing data in the target column will be lost. The purpose of this is to allow changing the type of a column with a Wire Graph configuration update.
"},{"location":"core-services/h2db-service/#enabling-the-tcp-server","title":"Enabling the TCP Server","text":"Danger
This feature is intended to be used only for debugging/development purposes. The server created by H2 is not running on a secure protocol. Only enable the server for a limited time and make sure to properly secure the firewall ports on which it is running.
The TCP server can be used by creating a H2DbServer instance:
org.eclipse.kura.core.db.H2DbServer
from the Factory drop-down\u200b list, enter an arbitrary name for the new instance and click Apply.The server, with the default configuration, will be listening on port 9123.
Tip
Make sure to review the firewall configuration in order to ensure that the server is reachable from an external process.
"},{"location":"core-services/h2db-service/#enabling-the-web-console","title":"Enabling the Web Console","text":"Danger
This feature is intended to be used only for debugging/development purposes. The server created by H2 is not running on a secure protocol. Only enable the server for a limited time and make sure to properly secure the firewall ports on which it is running.
In order to enable the H2 Web console, proceed as follows:
-webPort 9123 -webAllowOthers -ifExists -webExternalNames <device-ip>
.The server is now listening on the specified port.
Tip
Make sure to review the firewall configuration in order to ensure that the server is reachable from an external process.
Use a browser to access the console. Open the http://: URL, where is the IP address of the gateway and is the port specified at step 3.
Enter the DB URL as specified in the Kura configuration in the JDBC URL field and the credentials. Click on Connect, you should be able to access the console.
"},{"location":"core-services/h2db-service/#change-the-database-password","title":"Change the Database Password","text":"To change the database password the System Administrator needs to:
Warn
If the H2DbServer instance fails to open a database, it will delete and recreate all database files. This behavior\u200b is aimed at preventing potential issues caused by incorrect credentials in the configuration snapshots. It is highly recommended to perform a backup of an existing database before trying to open it using a H2DbService instance and before changing the password.
"},{"location":"core-services/h2db-service/#persistence-modes","title":"Persistence Modes","text":"The H2 database supports several persistence modes.
"},{"location":"core-services/h2db-service/#in-memory","title":"In Memory","text":"An in-memory database instance can be created using the following URL structure: jdbc:h2:mem:, where is a non-empty string that represents the database name. This configuration is suggested for database instances that are frequently updated. Examples:
The default database instance is in-memory by default and uses the jdbc:h2:mem:kuradb URL.
"},{"location":"core-services/h2db-service/#persistent","title":"Persistent","text":"A persistent database instance can be created using the jdbc:h2:file:, where is a non-empty string that represents the database path.
If no URL parameters are supplied the database will enable the transaction log by default. The transaction log is used to restore the database to a consistent state after a crash or power failure. This provides good protection against data losses but causes a lot of writes to the storage device, reducing both performance and the lifetime of flash-based storage devices.
Examples: - jdbc:h2:file:/opt/db/mydb
Make sure to use absolute paths in the DB URL since H2 does not support DB paths relative to the working directory.
"},{"location":"core-services/introduction/","title":"Introduction","text":"This section describes the administrative tools available using the Gateway Administration Console. This web interface provides the ability to configure all services and applications that are installed and running on the gateway.
"},{"location":"core-services/network-status-rest-v1/","title":"Network Status Service V1 REST APIs and MQTT Request Handler","text":"The NET-STATUS-V1 cloud request handler and the corresponding REST APIs allow to retrieve the current status of the network interfaces available on the system.
This cloud request handler and rest API is available only on the systems that provide a NetworkStatusService implementation, at the moment this corresponds to the devices that include the NetworkManager integration.
Accessing the REST APIs requires to use an identity with the rest.network.status
permission assigned.
failures
field of the response.failures
field of the responses.interfaceIds
field, it is null
or if it contains empty or null
interface ids.An object containing a list of network interface identifiers
Properties:
interfaceIds: array
The list of network interface identifiers
string
An interface identifier{\n \"interfaceIds\": [\n \"lo\"\n ]\n}\n
"},{"location":"core-services/network-status-rest-v1/#interfacestatuslist","title":"InterfaceStatusList","text":"An object reporting a list of network interface status. If a failure occurs retrieving the status for a specific interface, the reason will be reported in the failures
list.
Properties:
interfaces: array
A list of network interface status
variant
failures: array
object
{\n \"failures\": [],\n \"interfaces\": [\n {\n \"autoConnect\": true,\n \"driver\": \"unknown\",\n \"driverVersion\": \"\",\n \"firmwareVersion\": \"\",\n \"hardwareAddress\": \"00:00:00:00:00:00\",\n \"id\": \"lo\",\n \"interfaceIp4Addresses\": {\n \"addresses\": [\n {\n \"address\": \"127.0.0.1\",\n \"prefix\": 8\n }\n ],\n \"dnsServerAddresses\": []\n },\n \"interfaceName\": \"lo\",\n \"mtu\": 65536,\n \"state\": \"UNMANAGED\",\n \"type\": \"LOOPBACK\",\n \"virtual\": true\n }\n ]\n}\n
{\n \"failures\": [\n {\n \"interfaceId\": \"foo\",\n \"reason\": \"Not found.\"\n }\n ],\n \"interfaces\": []\n}\n
"},{"location":"core-services/network-status-rest-v1/#loopbackinterfacestatus","title":"LoopbackInterfaceStatus","text":"Object that contains specific properties to describe the status of an Loopback interface. It contains also all of the properties specified by NetworkInterfaceStatus.
Properties:
{\n \"autoConnect\": true,\n \"driver\": \"unknown\",\n \"driverVersion\": \"\",\n \"firmwareVersion\": \"\",\n \"hardwareAddress\": \"00:00:00:00:00:00\",\n \"id\": \"lo\",\n \"interfaceIp4Addresses\": {\n \"addresses\": [\n {\n \"address\": \"127.0.0.1\",\n \"prefix\": 8\n }\n ],\n \"dnsServerAddresses\": []\n },\n \"interfaceName\": \"lo\",\n \"mtu\": 65536,\n \"state\": \"UNMANAGED\",\n \"type\": \"LOOPBACK\",\n \"virtual\": true\n}\n
"},{"location":"core-services/network-status-rest-v1/#ethernetinterfacestatus","title":"EthernetInterfaceStatus","text":"Object that contains specific properties to describe the status of an Ethernet interface. It contains also all of the properties specified by NetworkInterfaceStatus.
Properties:
bool
{\n \"autoConnect\": true,\n \"driver\": \"igb\",\n \"driverVersion\": \"5.6.0-k\",\n \"firmwareVersion\": \"3.25, 0x800005d0\",\n \"hardwareAddress\": \"00:E0:C7:0A:5F:89\",\n \"id\": \"eno1\",\n \"interfaceIp4Addresses\": {\n \"addresses\": [\n {\n \"address\": \"172.16.0.1\",\n \"prefix\": 24\n }\n ],\n \"dnsServerAddresses\": [],\n \"gateway\": \"0.0.0.0\"\n },\n \"interfaceName\": \"eno1\",\n \"linkUp\": true,\n \"mtu\": 1500,\n \"state\": \"ACTIVATED\",\n \"type\": \"ETHERNET\",\n \"virtual\": false\n}\n
"},{"location":"core-services/network-status-rest-v1/#wifiinterfacestatus","title":"WifiInterfaceStatus","text":"Object that contains specific properties to describe the status of a WiFi interface. It contains also all of the properties specified by NetworkInterfaceStatus.
Properties:
capabilities: array
string (enumerated)
channels: array
object
countryCode: string
mode: string (enumerated)
activeWifiAccessPoint: object
(optional)
availableWifiAccessPoints: array
object
{\n \"activeWifiAccessPoint\": {\n \"channel\": {\n \"channel\": 11,\n \"frequency\": 2462\n },\n \"hardwareAddress\": \"11:22:33:44:55:66\",\n \"maxBitrate\": 130000,\n \"mode\": \"INFRA\",\n \"rsnSecurity\": [\n \"GROUP_CCMP\",\n \"KEY_MGMT_PSK\",\n \"PAIR_CCMP\"\n ],\n \"signalQuality\": 100,\n \"signalStrength\": -20,\n \"ssid\": \"MyAccessPoint\",\n \"wpaSecurity\": [\n \"NONE\"\n ]\n },\n \"autoConnect\": true,\n \"availableWifiAccessPoints\": [\n {\n \"channel\": {\n \"channel\": 11,\n \"frequency\": 2462\n },\n \"hardwareAddress\": \"11:22:33:44:55:66\",\n \"maxBitrate\": 130000,\n \"mode\": \"INFRA\",\n \"rsnSecurity\": [\n \"GROUP_CCMP\",\n \"KEY_MGMT_PSK\",\n \"PAIR_CCMP\"\n ],\n \"signalQuality\": 100,\n \"signalStrength\": -20,\n \"ssid\": \"MyAccessPoint\",\n \"wpaSecurity\": [\n \"NONE\"\n ]\n },\n {\n \"channel\": {\n \"channel\": 5,\n \"frequency\": 2432\n },\n \"hardwareAddress\": \"22:33:44:55:66:77\",\n \"maxBitrate\": 270000,\n \"mode\": \"INFRA\",\n \"rsnSecurity\": [\n \"GROUP_CCMP\",\n \"KEY_MGMT_PSK\",\n \"PAIR_CCMP\"\n ],\n \"signalQuality\": 42,\n \"signalStrength\": -69,\n \"ssid\": \"OtherSSID\",\n \"wpaSecurity\": [\n \"NONE\"\n ]\n }\n ],\n \"capabilities\": [\n \"CIPHER_WEP40\",\n \"WPA\",\n \"AP\",\n \"FREQ_VALID\",\n \"ADHOC\",\n \"RSN\",\n \"CIPHER_TKIP\",\n \"CIPHER_WEP104\",\n \"CIPHER_CCMP\",\n \"FREQ_2GHZ\"\n ],\n \"channels\": [\n {\n \"attenuation\": 20.0,\n \"channel\": 1,\n \"disabled\": false,\n \"frequency\": 2412,\n \"noInitiatingRadiation\": false,\n \"radarDetection\": false\n },\n {\n \"attenuation\": 20.0,\n \"channel\": 2,\n \"disabled\": false,\n \"frequency\": 2417,\n \"noInitiatingRadiation\": false,\n \"radarDetection\": false\n }\n ],\n \"countryCode\": \"IT\",\n \"driver\": \"brcmfmac\",\n \"driverVersion\": \"7.45.98.94\",\n \"firmwareVersion\": \"01-3b33decd\",\n \"hardwareAddress\": \"44:55:66:77:88:99\",\n \"id\": \"wlan0\",\n \"interfaceIp4Addresses\": {\n \"addresses\": [\n {\n \"address\": \"192.168.0.113\",\n \"prefix\": 24\n }\n ],\n \"dnsServerAddresses\": []\n },\n \"interfaceName\": \"wlan0\",\n \"mode\": \"INFRA\",\n \"mtu\": 1500,\n \"state\": \"ACTIVATED\",\n \"type\": \"WIFI\",\n \"virtual\": false\n}\n
{\n \"activeWifiAccessPoint\": {\n \"channel\": {\n \"channel\": 1,\n \"frequency\": 2412\n },\n \"hardwareAddress\": \"44:55:66:77:88:99\",\n \"maxBitrate\": 0,\n \"mode\": \"INFRA\",\n \"rsnSecurity\": [\n \"GROUP_CCMP\",\n \"KEY_MGMT_PSK\",\n \"PAIR_CCMP\"\n ],\n \"signalQuality\": 0,\n \"signalStrength\": -104,\n \"ssid\": \"kura_gateway_raspberry_pi\",\n \"wpaSecurity\": [\n \"NONE\"\n ]\n },\n \"autoConnect\": true,\n \"availableWifiAccessPoints\": [\n {\n \"channel\": {\n \"channel\": 1,\n \"frequency\": 2412\n },\n \"hardwareAddress\": \"44:55:66:77:88:99\",\n \"maxBitrate\": 0,\n \"mode\": \"INFRA\",\n \"rsnSecurity\": [\n \"GROUP_CCMP\",\n \"KEY_MGMT_PSK\",\n \"PAIR_CCMP\"\n ],\n \"signalQuality\": 0,\n \"signalStrength\": -104,\n \"ssid\": \"kura_gateway_raspberry_pi\",\n \"wpaSecurity\": [\n \"NONE\"\n ]\n }\n ],\n \"capabilities\": [\n \"CIPHER_WEP40\",\n \"WPA\",\n \"AP\",\n \"FREQ_VALID\",\n \"ADHOC\",\n \"RSN\",\n \"CIPHER_TKIP\",\n \"CIPHER_WEP104\",\n \"CIPHER_CCMP\",\n \"FREQ_2GHZ\"\n ],\n \"channels\": [\n {\n \"attenuation\": 20.0,\n \"channel\": 1,\n \"disabled\": false,\n \"frequency\": 2412,\n \"noInitiatingRadiation\": false,\n \"radarDetection\": false\n },\n {\n \"attenuation\": 20.0,\n \"channel\": 2,\n \"disabled\": false,\n \"frequency\": 2417,\n \"noInitiatingRadiation\": false,\n \"radarDetection\": false\n }\n ],\n \"countryCode\": \"00\",\n \"driver\": \"brcmfmac\",\n \"driverVersion\": \"7.45.98.94\",\n \"firmwareVersion\": \"01-3b33decd\",\n \"hardwareAddress\": \"44:55:66:77:88:99\",\n \"id\": \"wlan0\",\n \"interfaceIp4Addresses\": {\n \"addresses\": [\n {\n \"address\": \"172.16.1.1\",\n \"prefix\": 24\n }\n ],\n \"dnsServerAddresses\": []\n },\n \"interfaceName\": \"wlan0\",\n \"mode\": \"MASTER\",\n \"mtu\": 1500,\n \"state\": \"ACTIVATED\",\n \"type\": \"WIFI\",\n \"virtual\": false\n}\n
"},{"location":"core-services/network-status-rest-v1/#modeminterfacestatus","title":"ModemInterfaceStatus","text":"Object that contains specific properties to describe the status of a Modem interface. It contains also all of the properties specified by NetworkInterfaceStatus.
Properties:
model: string
manufacturer: string
serialNumber: string
softwareRevision: string
hardwareRevision: string
primaryPort: string
ports: object
supportedModemCapabilities: array
string (enumerated)
currentModemCapabilities: array
string (enumerated)
powerState: string (enumerated)
supportedModes: array
object
currentModes: object
supportedBands: array
string (enumerated)
currentBands: array
string (enumerated)
gpsSupported: bool
availableSims: array
object
simLocked: bool
bearers: array
object
connectionType: string (enumerated)
connectionStatus: string (enumerated)
accessTechnologies: array
string (enumerated)
signalQuality: number
signalStrength: number
registrationStatus: string (enumerated)
operatorName: string
{\n \"accessTechnologies\": [\n \"LTE\"\n ],\n \"autoConnect\": true,\n \"availableSims\": [\n {\n \"active\": true,\n \"primary\": true,\n \"eSimStatus\": \"UNKNOWN\",\n \"eid\": \"\",\n \"iccid\": \"1111111111111111111\",\n \"imsi\": \"111111111111111\",\n \"operatorName\": \"MyOperator\",\n \"operatorIdentifier\": \"12345\",\n \"simType\": \"PHYSICAL\"\n }\n ],\n \"bearers\": [\n {\n \"apn\": \"apn.myoperator.com\",\n \"bytesReceived\": 0,\n \"bytesTransmitted\": 0,\n \"connected\": true,\n \"ipTypes\": [\n \"IPV4\"\n ],\n \"name\": \"wwp11s0f2u3i4\"\n }\n ],\n \"connectionStatus\": \"CONNECTED\",\n \"connectionType\": \"DirectIP\",\n \"currentBands\": [\n \"DCS\",\n \"EUTRAN_3\",\n \"EUTRAN_19\",\n \"EUTRAN_40\",\n \"EUTRAN_26\",\n \"EUTRAN_28\",\n \"EUTRAN_41\",\n \"UTRAN_6\",\n \"EUTRAN_13\",\n \"EUTRAN_25\",\n \"EUTRAN_5\",\n \"EUTRAN_7\",\n \"EUTRAN_8\",\n \"UTRAN_2\",\n \"EUTRAN_38\",\n \"UTRAN_1\",\n \"EUTRAN_12\",\n \"UTRAN_8\",\n \"EUTRAN_18\",\n \"UTRAN_19\",\n \"G850\",\n \"EUTRAN_20\",\n \"UTRAN_5\",\n \"EUTRAN_1\",\n \"EUTRAN_39\",\n \"EUTRAN_2\",\n \"EUTRAN_4\",\n \"EGSM\",\n \"PCS\",\n \"UTRAN_4\"\n ],\n \"currentModemCapabilities\": [\n \"GSM_UMTS\",\n \"LTE\"\n ],\n \"currentModes\": {\n \"modes\": [\n \"MODE_2G\",\n \"MODE_3G\",\n \"MODE_4G\"\n ],\n \"preferredMode\": \"MODE_4G\"\n },\n \"driver\": \"qmi_wwan, option1\",\n \"driverVersion\": \"\",\n \"firmwareVersion\": \"\",\n \"gpsSupported\": true,\n \"hardwareAddress\": \"00:00:00:00:00:00\",\n \"hardwareRevision\": \"10000\",\n \"id\": \"1-3\",\n \"interfaceIp4Addresses\": {\n \"addresses\": [\n {\n \"address\": \"1.2.3.4\",\n \"prefix\": 30\n }\n ],\n \"dnsServerAddresses\": [\n \"1.2.3.6\",\n \"1.2.3.7\"\n ],\n \"gateway\": \"1.2.3.5\"\n },\n \"interfaceName\": \"wwp11s0f2u3i4\",\n \"manufacturer\": \"QUALCOMM INCORPORATED\",\n \"model\": \"QUECTEL Mobile Broadband Module\",\n \"mtu\": 1500,\n \"operatorName\": \"MyOperator\",\n \"ports\": {\n \"cdc-wdm0\": \"QMI\",\n \"ttyUSB0\": \"QCDM\",\n \"ttyUSB1\": \"GPS\",\n \"ttyUSB2\": \"AT\",\n \"ttyUSB3\": \"AT\",\n \"wwp11s0f2u3i4\": \"NET\"\n },\n \"powerState\": \"ON\",\n \"primaryPort\": \"cdc-wdm0\",\n \"registrationStatus\": \"HOME\",\n \"serialNumber\": \"111111111111111\",\n \"signalQuality\": 55,\n \"signalStrength\": -80,\n \"simLocked\": true,\n \"softwareRevision\": \"EG25GGBR07A08M2G\",\n \"state\": \"ACTIVATED\",\n \"supportedBands\": [\n \"DCS\",\n \"EUTRAN_3\",\n \"EUTRAN_19\",\n \"EUTRAN_40\",\n \"EUTRAN_26\",\n \"EUTRAN_28\",\n \"EUTRAN_41\",\n \"UTRAN_6\",\n \"EUTRAN_13\",\n \"EUTRAN_25\",\n \"EUTRAN_5\",\n \"EUTRAN_7\",\n \"EUTRAN_8\",\n \"UTRAN_2\",\n \"EUTRAN_38\",\n \"UTRAN_1\",\n \"EUTRAN_12\",\n \"UTRAN_8\",\n \"EUTRAN_18\",\n \"UTRAN_19\",\n \"G850\",\n \"EUTRAN_20\",\n \"UTRAN_5\",\n \"EUTRAN_1\",\n \"EUTRAN_39\",\n \"EUTRAN_2\",\n \"EUTRAN_4\",\n \"EGSM\",\n \"PCS\",\n \"UTRAN_4\"\n ],\n \"supportedModemCapabilities\": [\n \"NONE\"\n ],\n \"supportedModes\": [\n {\n \"modes\": [\n \"MODE_4G\"\n ],\n \"preferredMode\": \"NONE\"\n },\n {\n \"modes\": [\n \"MODE_2G\",\n \"MODE_3G\",\n \"MODE_4G\"\n ],\n \"preferredMode\": \"MODE_4G\"\n }\n ],\n \"type\": \"MODEM\",\n \"virtual\": false\n}\n
"},{"location":"core-services/network-status-rest-v1/#networkinterfacestatus","title":"NetworkInterfaceStatus","text":"This object contains the common properties contained by the status object reported for a network interface. A network interface is identified by Kura using the id field. It is used to internally manage the interface. The interfaceName, instead, is the IP interface as it may appear on the system. For Ethernet and WiFi interfaces the two values coincide (i.e. eth0, wlp1s0, ...). For modems, instead, the id is typically the usb or pci path, while the interfaceName is the IP interface created when they are connected. When the modem is disconnected the interfaceName can have a different value.
Properties:
id: string
interfaceName: string
hardwareAddress: string
driver: string
driverVersion: string
firmwareVersion: string
virtual: bool
state: string (enumerated)
autoConnect: bool
mtu: number
interfaceIp4Addresses: array
(optional)
object
interfaceIp6Addresses: array
(optional)
object
Represents an IPv4 or IPv6 addresses as a string.
"},{"location":"core-services/network-status-rest-v1/#hardwareaddress","title":"HardwareAddress","text":"Represents an hardware address as its bytes reported as two characters hexadecimal strings separated by the ':' character. e.g. 00:11:22:33:A4:FC:BB.
"},{"location":"core-services/network-status-rest-v1/#networkinterfaceipaddress","title":"NetworkInterfaceIpAddress","text":"This object describes an IP address with its prefix. It can be used for IPv4 or IPv6 addresses.
Properties:
address: string
prefix: number
This class describes the IP address status of a network interface: a list of IP addresses, an optional gateway and a list of DNS servers address. It can be used for IPv4 or IPv6 addresses.
Properties:
addresses: array
object
gateway: string
(optional This field can be missing if the interface has no gateway.)
dnsServerAddresses: array
string
This class represent a WiFi channel, providing the channel number, frequency, status and other useful information.
Properties:
channel: number
frequency: number
disabled: bool
(optional)
attenuation: number
(optional)
noInitiatingRadiation: bool
(optional)
radarDetection: bool
(optional)
This object describes a Wifi Access Point. It can be used both for describing a detected AP after a WiFi scan when in Station mode and the provided AP when in Master (or Access Point) mode.
Properties:
ssid: string
The Service Set IDentifier of the WiFi network
hardwareAddress: string
channel: object
mode: string (enumerated)
maxBitrate: number
The maximum bitrate this access point is capable of.
signalQuality: number
The current signal quality of the access point in percentage.
signalStrength: number
The current signal strength of the access point in dBm.
wpaSecurity: array
The WPA capabilities of the access point
string (enumerated)
rsnSecurity: array
The RSN capabilities of the access point
string (enumerated)
This object represents a pair of Modem Mode list and a preferred one.
Properties:
modes: array
string (enumerated)
preferredMode: string (enumerated)
This class contains all relevant properties to describe a SIM (Subscriber Identity Module).
Properties:
active: bool
primary: bool
iccid: string
imsi: string
eid: string
operatorName: string
operatorIdentifier: string
simType: string (enumerated)
eSimStatus: string (enumerated)
This object describes the Bearer or Context associated to a modem connection.
Properties:
name: string
connected: bool
apn: string
ipTypes: array
string (enumerated)
bytesTransmitted: number
bytesReceived: number
An object representing a set of modem ports. The members of this object represent modem ports, the member names represent the modem port name. This object can have a variable number of members.
Properties:
string (enumerated)
The type of a network interface.
UNKNOWN
: The device type is unknownETHERNET
: The device is a wired Ethernet device.WIFI
: The device is an 802.11 WiFi device.UNUSED1
UNUSED2
BT
: The device is a Bluetooth device.OLPC_MESH
: The device is an OLPC mesh networking device.WIMAX
: The device is an 802.16e Mobile WiMAX device.MODEM
: The device is a modem supporting one or more of analog telephone, CDMA/EVDO, GSM/UMTS/HSPA, or LTE standards to access a cellular or wireline data network.INFINIBAND
: The device is an IP-capable InfiniBand interface.BOND
: The device is a bond master interface.VLAN
: The device is a VLAN interface.ADSL
: The device is an ADSL device.BRIDGE
: The device is a bridge master interface.GENERIC
: This is a generic support for unrecognized device types.TEAM
: The device is a team master interface.TUN
: The device is a TUN or TAP interface.TUNNEL
: The device is an IP tunnel interface.MACVLAN
: The device is a MACVLAN interface.VXLAN
: The device is a VXLAN interface.VETH
: The device is a VETH interface.MACSEC
: The device is a MACsec interface.DUMMY
: The device is a dummy interface.PPP
: The device is a PPP interface.OVS_INTERFACE
: The device is a Open vSwitch interface.OVS_PORT
: The device is a Open vSwitch portOVS_BRIDGE
: The device is a Open vSwitch bridge.WPAN
: The device is a IEEE 802.15.4 (WPAN) MAC Layer Device.SIXLOWPAN
: The device is a 6LoWPAN interface.WIREGUARD
: The device is a WireGuard interface. WIFI_P2P
: The device is an 802.11 Wi-Fi P2P device.VRF
: The device is a VRF (Virtual Routing and Forwarding) interface.LOOPBACK
: The device is a loopback device.The state of a network interface.
UNKNOWN
: The device is in an unknown state.UNMANAGED
: The device cannot be used (carrier off, rfkill, etc).UNAVAILABLE
: The device is not connected.DISCONNECTED
: The device is preparing to connect.PREPARE
: The device is being configured.CONFIG
: The device is awaiting secrets necessary to continue connection.NEED_AUTH
: The IP settings of the device are being requested and configured.IP_CONFIG
: The device's IP connectivity ability is being determined.IP_CHECK
: The device is waiting for secondary connections to be activated.SECONDARIES
: The device is waiting for secondary connections to be activated.ACTIVATED
: The device is active.DEACTIVATING
: The device's network connection is being turn down.FAILED
: The device is in a failure state following an attempt to activate it.The capability of a WiFi interface.
NONE
: The device has no encryption/authentication capabilitiesCIPHER_WEP40
: The device supports 40/64-bit WEP encryption.CIPHER_WEP104
: The device supports 104/128-bit WEP encryption.CIPHER_TKIP
: The device supports the TKIP encryption.CIPHER_CCMP
: The device supports the AES/CCMP encryption.WPA
: The device supports the WPA1 encryption/authentication protocol.RSN
: The device supports the WPA2/RSN encryption/authentication protocol.AP
: The device supports Access Point mode.ADHOC
: The device supports Ad-Hoc mode.FREQ_VALID
: The device reports frequency capabilities.FREQ_2GHZ
: The device supports 2.4GHz frequencies.FREQ_5GHZ
: The device supports 5GHz frequencies.MESH
: The device supports mesh points.IBSS_RSN
: The device supports WPA2 in IBSS networksModes of operation for wifi interfaces
UNKNOWN
: Mode is unknown.ADHOC
: Uncoordinated network without central infrastructure.INFRA
: Client mode - Coordinated network with one or more central controllers.MASTER
: Access Point Mode - Coordinated network with one or more central controllers.Flags describing the security capabilities of an access point.
NONE
: NonePAIR_WEP40
: Supports pairwise 40-bit WEP encryption.PAIR_WEP104
: Supports pairwise 104-bit WEP encryption.PAIR_TKIP
: Supports pairwise TKIP encryption.PAIR_CCMP
: Supports pairwise CCMP encryption.GROUP_WEP40
: Supports a group 40-bit WEP cipher.GROUP_WEP104
: Supports a group 104-bit WEP cipher.GROUP_TKIP
: Supports a group TKIP cipher.GROUP_CCMP
: Supports a group CCMP cipher.KEY_MGMT_PSK
: Supports PSK key management.KEY_MGMT_802_1X
: Supports 802.1x key management.SECURITY_NONE
: Supports no encryption.SECURITY_WEP
: Supports WEP encryption.SECURITY_WPA
: Supports WPA encryption.SECURITY_WPA2
: Supports WPA2 encryption.SECURITY_WPA_WPA2
: Supports WPA and WPA2 encryption.The type of a modem port.
UNKNOWN
NET
AT
QCDM
GPS
QMI
MBIM
AUDIO
IGNORED
The generic access technologies families supported by a modem.
NONE
: The modem has no capabilities.POTS
: The modem supports the Plain Old Telephone Service (analog wired telephone network).EVDO
: The modem supports EVDO revision 0, A or B.GSM_UMTS
: The modem supports at least one of GSM, GPRS, EDGE, UMTS, HSDPA, HSUPA or HSPA+ technologies.LTE
: The modem has LTE capabilities.IRIDIUM
: The modem supports Iridium technology.FIVE_GNR
: The modem supports 5GNR.TDS
: The modem supports TDS.ANY
: The modem supports all capabilities.The generic access mode a modem supports.
NONE
CS
MODE_2G
MODE_3G
MODE_4G
MODE_5G
ANY
The radio bands supported by a modem when connected to a mobile network.
UNKNOWN
EGSM
DCS
PCS
G850
UTRAN_1
UTRAN_3
UTRAN_4
UTRAN_6
UTRAN_5
UTRAN_8
UTRAN_9
UTRAN_2
UTRAN_7
G450
G480
G750
G380
G410
G710
G810
EUTRAN_1
EUTRAN_2
EUTRAN_3
EUTRAN_4
EUTRAN_5
EUTRAN_6
EUTRAN_7
EUTRAN_8
EUTRAN_9
EUTRAN_10
EUTRAN_11
EUTRAN_12
EUTRAN_13
EUTRAN_14
EUTRAN_17
EUTRAN_18
EUTRAN_19
EUTRAN_20
EUTRAN_21
EUTRAN_22
EUTRAN_23
EUTRAN_24
EUTRAN_25
EUTRAN_26
EUTRAN_27
EUTRAN_28
EUTRAN_29
EUTRAN_30
EUTRAN_31
EUTRAN_32
EUTRAN_33
EUTRAN_34
EUTRAN_35
EUTRAN_36
EUTRAN_37
EUTRAN_38
EUTRAN_39
EUTRAN_40
EUTRAN_41
EUTRAN_42
EUTRAN_43
EUTRAN_44
EUTRAN_45
EUTRAN_46
EUTRAN_47
EUTRAN_48
EUTRAN_49
EUTRAN_50
EUTRAN_51
EUTRAN_52
EUTRAN_53
EUTRAN_54
EUTRAN_55
EUTRAN_56
EUTRAN_57
EUTRAN_58
EUTRAN_59
EUTRAN_60
EUTRAN_61
EUTRAN_62
EUTRAN_63
EUTRAN_64
EUTRAN_65
EUTRAN_66
EUTRAN_67
EUTRAN_68
EUTRAN_69
EUTRAN_70
EUTRAN_71
EUTRAN_85
CDMA_BC0
CDMA_BC1
CDMA_BC2
CDMA_BC3
CDMA_BC4
CDMA_BC5
CDMA_BC6
CDMA_BC7
CDMA_BC8
CDMA_BC9
CDMA_BC10
CDMA_BC11
CDMA_BC12
CDMA_BC13
CDMA_BC14
CDMA_BC15
CDMA_BC16
CDMA_BC17
CDMA_BC18
CDMA_BC19
UTRAN_10
UTRAN_11
UTRAN_12
UTRAN_13
UTRAN_14
UTRAN_19
UTRAN_20
UTRAN_21
UTRAN_22
UTRAN_25
UTRAN_26
UTRAN_32
ANY
NGRAN_1
NGRAN_2
NGRAN_3
NGRAN_5
NGRAN_7
NGRAN_8
NGRAN_12
NGRAN_13
NGRAN_14
NGRAN_18
NGRAN_20
NGRAN_25
NGRAN_26
NGRAN_28
NGRAN_29
NGRAN_30
NGRAN_34
NGRAN_38
NGRAN_39
NGRAN_40
NGRAN_41
NGRAN_48
NGRAN_50
NGRAN_51
NGRAN_53
NGRAN_65
NGRAN_66
NGRAN_70
NGRAN_71
NGRAN_74
NGRAN_75
NGRAN_76
NGRAN_77
NGRAN_78
NGRAN_79
NGRAN_80
NGRAN_81
NGRAN_82
NGRAN_83
NGRAN_84
NGRAN_86
NGRAN_89
NGRAN_90
NGRAN_91
NGRAN_92
NGRAN_93
NGRAN_94
NGRAN_95
NGRAN_257
NGRAN_258
NGRAN_260
NGRAN_261
The SIM (Subscriber Identity Module) type.
UNKNOWN
PHYSICAL
ESIM
The status of an ESIM.
UNKNOWN
NO_PROFILES
WITH_PROFILES
The type of Bearer or Context associated to a modem connection.
NONE
IPV4
IPV6
IPV4V6
NON_IP
ANY
PPP
: Point to Point ProtocolDirectIP
: Direct IPThe status of a modem.
FAILED
: The modem is unavailableUNKNOWN
: The modem is in an unknown state.INITIALIZING
: The modem is being initialised.LOCKED
: The modem is locked.DISABLED
: The modem is disabled and powered off.DISABLING
: The modem is disabling.ENABLING
: The modem is enabling..ENABLED
: The modem is enabled but not registered to a network provider.SEARCHING
: The modem is searching for a network provider.REGISTERED
: The modem is registered to a network provider.DISCONNECTING
: The modem is disconnecting.CONNECTING
: The modem is connecting.CONNECTED
: The modem is connected.The specific technology types used when a modem is connected or registered to a network.
UNKNOWN
POTS
GSM
GSM_COMPACT
GPRS
EDGE
UMTS
HSDPA
HSUPA
HSPA
HSPA_PLUS
ONEXRTT
EVDO0
EVDOA
EVDOB
LTE
FIVEGNR
LTE_CAT_M
LTE_NB_IOT
ANY
The registration status of a modem when connected to a mobile network.
IDLE
HOME
SEARCHING
DENIED
UNKNOWN
ROAMING
HOME_SMS_ONLY
ROAMING_SMS_ONLY
EMERGENCY_ONLY
HOME_CSFB_NOT_PREFERRED
ROAMING_CSFB_NOT_PREFERRED
ATTACHED_RLOS
An object reporting a failure while retrieving the status of a specific network interface
Properties:
interfaceId: string
The identifier of the interface whose status cannot be retrieved.
reason: string
A message describing the reason of the failure.
An object reporting a failure message.
Properties:
string
A message describing the failure.The Nvidia\u2122 Triton Server is an open-source inference service software that enables the user to deploy trained AI models from any framework on GPU or CPU infrastructure. It supports all major frameworks like TensorFlow, TensorRT, PyTorch, ONNX Runtime, and even custom framework backend. With specific backends, it is also possible to run Python scripts, mainly for pre-and post-processing purposes, and exploit the DALI building block for optimized operations. For more detail about the Triton Server, please refer to the official website.
Kura provides three components for exposing the Triton Server service functionality which implement the inference engine APIs and provides methods for interacting with a local or remote Nvidia\u2122 Triton Server:
Before running Kura's Triton Server Service, you must install the Triton Inference Server. Here you can find the necessary steps for the available suggested installation methods.
"},{"location":"core-services/nvidia-triton-server-inference-engine/#native-triton-installation-on-jetson-devices","title":"Native Triton installation on Jetson devices","text":"A release of Triton for JetPack is provided in the tar file in the Triton Inference Server release notes. Full documentation is available here.
Installation steps:
bin
folder.tritonserver
executable to your path or symlinking the executable to /usr/local/bin
.Before you can use the Triton Docker image you must install Docker. If you plan on using a GPU for inference you must also install the NVIDIA Container Toolkit.
Pull the image using the following command.
$ docker pull nvcr.io/nvidia/tritonserver:<xx.yy>-py3\n
Where <xx.yy>
is the version of Triton that you want to pull.
The official docs mention the possibility to perform a native installation on supported platform by extracting the binaries from the Docker images. To do so you must install the necessary dependencies (some can be found in the Jetson runtime dependencies docs) on the system. For Triton to support NVIDIA GPUs you must install CUDA, cuBLAS and cuDNN referencing the support matrix.
Note
For Python models the libraries available to the Python model are the ones available for the user running the Triton server. Therefore you'll need to install the libraries through pip
for the kurad
user.
The Triton Inference Server serves models from one or more model repositories that are specified when the server is started. The model repository is the directory where you place the models that you want Triton to serve. Be sure to follow the instructions to setup the model repository directory.
Further information about an example Triton Server setup can be found in the official documentation.
"},{"location":"core-services/nvidia-triton-server-inference-engine/#triton-server-remote-service-component","title":"Triton Server Remote Service component","text":"The Kura Triton Server Remote Service component is the implementation of the inference engine APIs and provides methods for interacting with a remote (i.e. unmnanaged) Nvidia\u2122 Triton Server. As presented below, the component enables the user to communicate to an external server to load specific models. With this component the server lifecycle (startup, shutdown) won't be handled by Kura and it's the user responsibility to make it available to Kura for connecting.
The parameters used to configure the Triton Service are the following:
io.grpc.StatusRuntimeException: RESOURCE_EXHAUSTED: gRPC message exceeds maximum size 4194304\n
Note
Pay attention on the ports used for communicating with the Triton Server. The default ports are the 8000-8002, but these are tipically used by Kura for debug purposes.
"},{"location":"core-services/nvidia-triton-server-inference-engine/#triton-server-native-service-component","title":"Triton Server Native Service component","text":"The Kura Triton Server component is the implementation of the inference engine APIs and provides methods for interacting with a local native Nvidia\u2122 Triton Server. As presented below, the component enables the user to configure a local server running on the gateway and handles its lifecycle. This operating mode supports more features for interacting with the server like the AI Model Encryption.
Note
Requirement: tritonserver
executable needs to be available in the path to the kurad
user. Be sure to have a working Triton Server installation before configuring the local native Triton Server instance through Kura UI.
The parameters used to configure the Triton Service are the following:
Note
Pay attention on the ports used for communicating with the Triton Server. The default ports are the 8000-8002, but these are tipically used by Kura for debug purposes.
"},{"location":"core-services/nvidia-triton-server-inference-engine/#triton-server-container-service-component","title":"Triton Server Container Service component","text":"The Kura Triton Server component is the implementation of the inference engine APIs and provides methods for interacting with a local container running the Nvidia\u2122 Triton Server. As presented below, the component enables the user to configure a local server running on the gateway and handles its lifecycle. This operating mode supports more features for interacting with the server like the AI Model Encryption.
Note
Requirement: 1. Triton Server container image already installed on the device. For instructions refer to the installation section in this page. 2. Kura's Container Orchestration Service enabled.
The parameters used to configure the Triton Service are the following:
nvidia
corresponds to --runtime=nvidia
. Note: when using the Nvidia Container Runtime, leave the GPUs field empty. The GPUs available on the system will be accessible from the container by default./dev/video0
).Note
Pay attention on the ports used for communicating with the Triton Server. The default ports are the 8000-8002, but these are typically used by Kura for debug purposes.
"},{"location":"core-services/nvidia-triton-server-inference-engine/#triton-server-service-component-deprecated-since-520","title":"Triton Server Service component [deprecated since 5.2.0]","text":"The Kura Triton Server component is the implementation of the inference engine APIs and provides methods for interacting with a local or remote Nvidia\u2122 Triton Server. As presented below, the component enables the user to configure a local server running on the gateway or to communicate to an external server to load specific models.
The parameters used to configure the Triton Service are the following:
Note
Pay attention on the ports used for communicating with the Triton Server. The default ports are the 8000-8002, but these are tipically used by Kura for debug purposes.
"},{"location":"core-services/nvidia-triton-server-inference-engine/#configuration-for-a-local-native-triton-server-with-triton-server-service-component-deprecated-since-520","title":"Configuration for a local native Triton Server with Triton Server Service component [deprecated since 5.2.0]","text":"Note
Requirement: tritonserver
executable needs to be available in the path to the kurad
user. Be sure to have a working Triton Server installation before configuring the local native Triton Server instance through Kura UI.
When the Local Nvidia Triton Server option is set to true, a local instance of the Nvidia\u2122 Triton Server is started on the gateway. The following configuration is required:
The typical command used to start the Triton Server is like this:
tritonserver --model-repository=<model_repository_path> \\\n--backend-directory=<backend_repository_path> \\\n--backend-config=<backend_config> \\\n--http-port=<http_port> \\\n--grpc-port=<grpc_port> \\\n--metrics-port=<metrics_port> \\\n--model-control-mode=explicit \\\n--load-model=<model_name_1> \\\n--load-model=<model_name_2> \\\n...\n
"},{"location":"core-services/nvidia-triton-server-inference-engine/#configuration-for-a-local-triton-server-running-in-a-docker-container-with-triton-server-service-component-deprecated-since-520","title":"Configuration for a local Triton Server running in a Docker container with Triton Server Service component [deprecated since 5.2.0]","text":"If the Nvidia\u2122 Triton Server is running as a Docker container in the gateway, the following configuration is required:
In order to correctly load the models at runtime, configure the server with the --model-control-mode=explicit
option. The typical command used for running the docker container is as follows. Note the forward of the ports to not interfere with Kura.
docker run --rm \\\n-p4000:8000 \\\n-p4001:8001 \\\n-p4002:8002 \\\n--shm-size=150m \\\n-v path/to/models:/models \\\nnvcr.io/nvidia/tritonserver:[version] \\\ntritonserver --model-repository=/models --model-control-mode=explicit\n
"},{"location":"core-services/nvidia-triton-server-inference-engine/#configuration-for-a-remote-triton-server-with-triton-server-service-component-deprecated-since-520","title":"Configuration for a remote Triton Server with Triton Server Service component [deprecated since 5.2.0]","text":"When the Nvidia\u2122 Triton Server is running on a remote server, the following configuration is needed:
For ensuring inference integrity and providing copyright protection of deep-learning models on edge devices, Kura provides decryption capabilities for trained models to be served through the Triton Server.
"},{"location":"core-services/nvidia-triton-server-inference-engine/#how-it-works","title":"How it works","text":"Prerequisites: a deep-learning trained model (or more) exists with the corresponding necessary configuration for running on the Triton Server without encryption. A folder containing the required files (model, configuration etc) has been tested on a Triton Server.
Restrictions: if model encryption is used, the following restrictions apply:
Once the development of the deep-learning model is complete, the developer who wants to deploy the model on the edge device in a secure manner can proceed with encrypting the Triton model using the procedure detailed below. After encrypting the model he/she can transfer the file on the edge device using his/her preferred method.
Kura will keep the stored model protected at all times and have the model decrypted in runtime only for use by the Inference Server Runtime. As soon as the model is correctly loaded into memory the decrypted model will be removed from the filesystem.
As an additional security measure, the Model Repository containing the decrypted models will be stored in a temporary subfolder and will feature restrictive permission such that only Kura, the Inference Server and the root
user will be able to access it.
Given a trained model inside the folder tf_autoencoder_fp32
(for example) with the following layout (see the official documentation for details):
tf_autoencoder_fp32\n\u251c\u2500\u2500 1\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 model.savedmodel\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 assets\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 keras_metadata.pb\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 saved_model.pb\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 variables\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 variables.data-00000-of-00001\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 variables.index\n\u2514\u2500\u2500 config.pbtxt\n
Compress the model into a zip archive with the following command:
zip -vr tf_autoencoder_fp32.zip tf_autoencoder_fp32/\n
then encrypt it with the AES 256 algorithm using the following gpg
command:
gpg --armor --symmetric --cipher-algo AES256 tf_autoencoder_fp32.zip\n
The resulting archive tf_autoencoder_fp32.zip.asc
can be transferred to the Local Model Repository Path on the target machine and will be decrypted by Kura.
The PositionService provides the geographic position of the gateway if a GPS component is available and enabled.
When this service is enabled and provides a valid geographic position, this position is published in the gateway birth certificate with its location.
The GPS connection parameters must be defined in order to allow the service to receive the GPS frames. The PositionService supports direct access to gps device or the connection to that through gpsd.
For a device that is not connected to a GPS, it is possible to define a static position by entering latitude, longitude,, altitude and GNSS Type. In this case, the position, date and time information is returned by the PositionService as if it were an actual GPS position. This may be useful when a gateway is installed in a known place and does not move.
To use this service, select the PositionService option located in the Services area as shown in the screen capture below.
This service provides the following configuration parameters:
enabled - defines whether or not this service is enabled or disabled. (Required field.)
static - specifies true or false whether to use a static position instead of a GPS. (Required field.)
provider - species which position provider use, can be gpsd or serial.
gpsd.host - host where gpsd service deamon is running. (required only if gpsd provider is selected.)
gpsd.port - port where gpsd service is listening. (required only if gpsd provider is selected.)
latitude - provides the static latitude value in degrees.
longitude - provides the static longitude value in degrees.
altitude - provides the static altitude value in meters.
GNSS Type - provides the gnss system used to retrieve static information.
port - supplies the USB or serial port of the GPS device.
baudRate - supplies the baud rate of the GPS device.
bitsPerWord - sets the number of bits per word (databits) for the serial communication to the GPS device.
stopbits - sets the number of stop bits for the serial communication to the GPS device.
parity - sets the parity for the serial communication to the GPS device.
Kura provides a built-in REST Service based on the osgi-jax-rs-connector project.
By default, REST service providers register their services using the context path /services
. The REST service provides the BASIC Authentication support and HTTPS client certificate authentication support.
Starting from Kura 5.4.0, REST service provides built in session management support, the Session REST APIs can be used to establish a session. Using sessions is the recommended way for interacting with Kura REST APIs from a browser based application, for this use case it is also possible to disable the default session-less BASIC and certificate based authentication (see the Basic Authentication Enabled and Enable Certificate Authentication Whitout Session Management configuration parameters below).
REST API access is available on all HTTP ports defined in the HTTP/HTTPS Configuration section, unless access is restricted to dedicated ports using the corresponding configuration parameter (see below).
Certificate authentication support is only available on the HTTPS With Certificate Authentication Ports configured in HTTP/HTTPS Configuration section.
Kura Identity names and passwords can be used for BASIC Authentication. Certificate authentication follows the same rules as Gateway Administration Console Authentication.
Warning
If the forced password change feature for a given identity is enabled, REST API password authentication will be blocked for that identity until the password is updated by the user or the feature is manually disabled. Certificate authentication will continue to be allowed even if the forced password change feature is enabled.
JAX-RS roles are mapped to Kura permissions, the name of a permission associated with a JAX-RS role is the rest. prefix followed by the role name. For example the assets role is mapped to the rest.assets permission. REST related permissions can be assigned to an identity using the Gateway Administration Console in the Identities section.
"},{"location":"core-services/rest-service/#rest-service-configuration","title":"Rest Service configuration","text":"The available configuration parameters are the following:
Allowed Ports: If set to a non empty list, REST API access will be allowed only on the specified ports. If set to an empty list, access will be allowed on all ports. Please make sure that the allowed ports are open in HttpService and Firewall configuration. (Default: empty)
Password Authentication Enabled: Enables or disables the built-in password authentication support. (Default: true)
Certificate Authentication Enabled: Enables or disables the built-in certificate authentication support. (Default: true)
Session Based Authentication Enabled: If set to true, enables authentication using the dedicated /services/session/v1
endpoints and cookie based session management. (Default: true)
Session Inactivity Interval (Seconds): The session inactivity interval, sessions will expire if no request is performed for the amount of time specified by this parameter in seconds. This parameter is ignored if Session Based Authentication Enabled is set to false. (Default: 900)
Basic Authentication Enabled: Allows to perform authentication by providing identity name and password as BASIC credentials in the request to any resource endpoint. Requires that the Password Authentication Enabled parameter is set to true. (Default: true)
Enable Certificate Authentication Without Session Management: If set to true, calling /services/session/v1/certificate
to create a session will not be necessary in order to perform certificate based authentication. Presenting a valid HTTPS client certificate and accessing resource endpoint directly is enough for authentication to succeed. Requires that the Certificate Authentication Enabled parameter is set to true. (Default: true)
Starting from Kura 5.2.0 it is also possible to develop custom REST authentication method providers by registering an implementation of the org.eclipse.kura.rest.auth.AuthenticationProvider
interface as an OSGi service. The org.eclipse.kura.example.rest.authentication.provider
bundle in Kura repository provides an example on how to implement a custom authentication method.
Kura exposes REST APIs for the Asset instances instantiated in the framework. Assets REST APIs are available in the context path /services/assets
. Following, the supported REST endpoints.
/
assets JSON None Returns the list of available assets GET /{pid}
assets JSON None Returns the list of available channels for the selected asset (specified by the corresponding PID) GET /{pid}/_read
assets JSON None Returns the read for all the READ channels in the selected Asset POST /{pid}/_read
assets JSON The list of channels where the READ operation should be performed. Returns the result of the read operation for the specified channels POST /{pid}/_write
assets JSON The list of channels and associated values that will be used for the WRITE operation. Performs the write operation for the specified channels returning the result of the operation."},{"location":"core-services/simple-artemis-mqtt-broker/","title":"Simple Artemis MQTT Broker","text":"By default, this instance is disabled but, selecting the Simple Artemis MQTT Broker option in Services it is possible to enable a basic instance of an \u200bActiveMQ-7 broker with MQTT capabilities.
The service has the following configuration fields:
Starting from version 5.3, Kura provides provides an integration of the SQLite database, based on the org.xerial:sqlite-jdbc wrapper .
The database integration is not included in the official distribution, but it can be downloaded from Eclipse Marketplace as a deployment package.
Warning
Note about Raspberry PI: Recent versions of Raspberry Pi OS 32 bit on Raspberry PI 4 will use by default a 64 bit kernel with a 32 bit userspace. This can cause issues to applications that use the result of uname -m
to decide which native libraries to load (see https://github.com/raspberrypi/firmware/issues/1795). This currently affects the Kura SQLite database connector. It should be possible to solve by switching to the 32 bit kernel setting arm_64bit=0
in /boot/config.txt
and restarting the device.
Kura supports the following SQLite database features:
Persistence modes: The implementation currently supports in-memory and file-based database instances.
Multiple database instances: It is possible to create and configure multiple database instances from the Kura Administration UI, these instances can be selectively consumed by applications.
Journaling modes: The implementation currently supports the WAL and rollback journal journaling modes.
Periodic database defrag and checkpoint: The implementations currently supports periodic defrag (VACUUM) and periodic WAL checkpoint.
To create a new SQLite database instance, use the following procedure:
org.eclipse.kura.db.SQLiteDbService
from the Factory drop-down list, enter an arbitrary name for the new instance and click Apply.The SQLite DB provides the following configuration parameters:
Database Mode: Defines the database mode. If In Memory
is selected, the database will not be persisted on the filesystem, all data will be lost if Kura is restarted and/or the database instance is deleted. If Persisted
is selected, the database will be stored on disk in the location specified by the Persisted Database Path parameter.
Persisted Database Path: Defines the path to the database file (it must include the database file name). This parameter is only relevant for persisted databases.
Encryption Key: Allows to specify a key/passphrase for encrypting the database file. This feature requires a SQLite binary with an encryption extension, and is only relevant for persisted databases. The key format can be specified using the Encryption Key Format parameter. If the value of this parameter is changed, the encryption key of the database will be updated accordingly. This parameter can be left empty to create an unencrypted database or to decrypt an encrypted one.
Note
The sqlite-jdbc version distributed with Kura does not contain any encryption extension, encryption features will not be available out of the box. See sqlite-jdbc documentaton for instructions about how to use a security extension.
Encryption Key Format: Allows to specify the format of the Encryption Key parameter value. The possible values are ASCII (an ASCII string), Hex SSE (the key is an hexadecimal string to be used with the SSE extension) or Hex SQLCipher (the key is an hexadecimal string to be used with the SQLCipher extension).
Journal Mode: The database journal mode. The following options are available:
Rollback Journal: The database instance will use the rollback journal for more details. More specifically, the DELETE argument will be passed to the pragma journal_mode command.
WAL: The database instance will use WAL mode. This is the default mode.
The WAL mode description page contains a comparison of the two modes.
Defrag enabled: Enables or disables the database defragmentation. Use the Defrag Interval parameter to specify the interval.
Defrag interval (seconds): The implementation supports running periodic defragmentation using the VACUUM command. This parameter specifies the interval in minutes between two successive checkpoints, set to zero to disable. This parameter is only relevant for persisted databases.
Warning
The total disk space used by SQLite database files might temporarily increase during defragmentation and/or if transactions that modify a lot of data are performed (including deletion). In particular:
It is recommended to perform some tests to determine the maximum database files size that will be used by the application and ensure that the size of the partition containing the database is at least twice as the expected db size.
WAL Checkpoint Interval (Seconds): The implementation supports running periodic periodic WAL checkpoints. Checkpoints will be performed in TRUNCATE mode. This parameter specifies the interval in seconds between two consecutive checkpoints, set to zero to disable. This parameter is only relevant for persisted databases in WAL Journal Mode. In WAL mode a checkpoint will be performed after a periodic defragmentation regardless of the value of this parameter.
Connection pool max size: The implementation manages connections using a connection pool. This parameter defines the maximum number of connections for the pool. If a new connection is requested
Delete Database Files On Failure: If set to true, the database files will be deleted in case of failure in opening a persisted database. This is intended as a last resort measure for keeping the database service operational, especially in the case when it is used as a cloud connection message store.
Debug Shell Access Enabled: Enables or disables the interaction with this database instance using the sqlitedbg:excuteQuery
OSGi console command. (see #debug-shell)
A database instance is identified by its Kura service PID. The PID for instances created using the Web UI is the string entered in the Name field at step 2 of the previous section.
The built-in components that use database functionalities allow to specify which instance to use in their configuration. These components are the DataService component of the cloud stack, the Wire Record Store and Wire Record Query wire components. The configuration of each component contains a property that allows to specify the Kura Service PID of the desired instance.
Warning
Using SQLite database instances through the deprecated DbFilter and DbStore components is not supported.
"},{"location":"core-services/sqlite-db-service/#usage-through-wires","title":"Usage through Wires","text":"It is possible to store and extract Wire Records into/from a SQLite database instance using the Wire Record Store and Wire Record Query wire components.
When a Wire Record is received by a Wire Record Store attached to a SQLite based database instance, the data will be stored in a table whose name is the current value of the Record Collection Name configuration parameter of the Wire Component.
Each property contained in a Wire Record will be appended to a column with the same name as the property key. A new column will be created if it doesn't already exists.
Since it is not possible to establish a one to one mapping between SQLite storage classes and the data types available on the Wires, the implementation will assign a custom type name to the created columns in order to keep track of the inserted Wire Record property type.
The custom types will be assigned according to the following table:
Wires Data Type Column Type Name Storage Class Type Affinity BOOLEAN BOOLEAN INTEGER INTEGER INT INTEGER LONG BIGINT INTEGER FLOAT FLOAT REAL DOUBLE DOUBLE REAL STRING TEXT TEXT BYTE_ARRAY BLOB BLOBThe custom column type makes it possible to preserve the original type when data is extracted with the Wire Record Query component. Please note that the resulting type may change in case of queries that build computed columns.
Warning
It is not recommended to store Wire Records having properties with the same key and different value type. If the value type changes, the target column will be dropped and recreated with the type derived from the last received record. All existing data in the target column will be lost. The purpose of this is to allow changing the type of a column with a Wire Graph configuration update.
"},{"location":"core-services/sqlite-db-service/#debug-shell","title":"Debug shell","text":"It is possible to inspect the contents of the database file using the OSGi console with the following command:
sqlitedbg:executeQuery dbServicePid 'query'\n
or more simply
executeQuery dbServicePid 'query'\n
where dbServicePid
is the user defined pid of the target database instance and query
is an arbitrary SQL query to be executed (make sure to properly quote the query string with the '
character). The command will print the result set or changed row count on the console.
It is only possible to access database instances whose Debug Shell Access Enabled configuration parameter is set to true
. The default of this parameter is false
.
The OSGi console is disabled by default, it can be accessed by starting the framework with the /opt/eclipse/kura/bin/start_kura_debug.sh
script and running the following command on the gateway:
telnet localhost 5002\n
Warning
This feature is intended for debug purposes only, the Debug Shell Access Enabled parameter as well as the OSGi console should not be left enabled on production systems.
"},{"location":"core-services/watchdog-service/","title":"Watchdog Service","text":"The WatchdogService provides methods for starting, stopping, and updating a hardware watchdog if it is present on the system. Once started, the watchdog must be updated to prevent the system from rebooting.
To use this service, select the WatchdogService option located in the Services area as shown in the screen capture below.
This service provides the following configuration parameters:
enabled - sets whether or not this service is enabled or disabled. (Required field)
pingInterval - defines the maximum time interval between two watchdogs' refresh to prevent the system from rebooting. (Required field)
Watchdog device path - sets the watchdog device path. (Required field)
Reboot Cause File Path - sets the path to the file that will contain the reboot cause information. (Required field)
Kura 5 introduces a centralized authentication and authorization framework based on the OSGi UserAdmin specification. This framework introduces the concepts of identities and permissions:
Identity: A Kura identity is related to authentication, an identity has a name and a set of associated credentials, for example a password.
Permission: A Kura permission is related to authorization. Zero or more permissions can be assigned to a given identity. Each permission allows to access a set of resources and/or perform certain operations. Permissions can be defined by applications.
Examples of applications that use the new authentication and authorization framework are the Web Console and the REST API framework:
ConfigurationService
based user and role definition mechanism has been dropped.The authentication and authorization framework only allows to define and store identities and permissions, it does not provide implementation of authentication methods and/or session management. These aspects are left to applications.
"},{"location":"gateway-configuration/authentication-and-authorization/#permission-and-identity-representation","title":"Permission and identity representation","text":"Permissions and identities are implemented on top of the UserAdmin User and Group concepts. See OSGi UserAdmin specification for more details on the Role, User and Group concepts.
"},{"location":"gateway-configuration/authentication-and-authorization/#identityservice-java-apis","title":"IdentityService Java APIs","text":"Kura 5.5 introduces a new set of Java APIs that allow to manage Kura identities, the implementation is based on the UserAdmin conventions described in this page, and allows to manipulate Kura identities without interacting directly with the UserAdmin. Please refer to the Javadoc for more details.
The new APIs also provide the capability to implement and register IdentityConfigurationExtensions in the framework.
An IdentityConfigurationExtension can define additional custom configuration parameters for each identity. The custom configuration can be inspected and modified in the Identities section of Kura Web UI and using the identity/v2 rest APIs and MQTT request handler. The IdentityConfigurationExtension implementation can store the additional configuration in the way that is most suitable for the application, for example by adding custom UserAdmin properties or credentials.
"},{"location":"gateway-configuration/authentication-and-authorization/#identities","title":"Identities","text":"A Kura identity is represented as a UserAdmin User with the following properties:
The User name must be in the kura.user.${identity_name}
form where ${identity_name}
is a non empty string representing the identity name. The name of an User representing a Kura identity must start with the kura.user.
prefix.
A password may be assigned to an identity by defining a property in User credentials with the following format:
kura.password
String org.eclipse.kura.crypto.CryptoService.sha256Hash(String)\n
method.Starting from Kura 5.1, it is possible to force an identity to change the password at next login by setting the following property in User properties: - kura.need.password.change
: true
encoded as a JSON string. - The property will be cleared automatically after a successful password change on next login.
Starting from Kura 5.5 the following restrictions will be applied by the IdentityService:
[A-Za-z0-9]+
) separated by the dot or underscore symbols, dot and underscore is not allowed at the beginning or at the end of the permission name, sequences of consecutive dots and/or underscores are not allowed (examples of valid names are foo1.bAr
, foo
, a.b.c
, foo.bar_baz
).A Kura permission is represented as a UserAdmin Group with the following properties:
The Group name must be in the kura.permission.${permission_name}
form where ${permission_name}
is a non empty string representing the permission name. The name of a Group representing a Kura permission must start with the kura.permission.
prefix.
Assigning a permission to a specific identity can be done by adding the User representing the identity to the basic members of the Group representing the permission.
Starting from Kura 5.5 the following restrictions will be applied by the IdentityService to the name new permissions:
[A-Za-z0-9]+
) separated by the dot symbol, the dot is not allowed at the beginning or at the end of the permission name (examples of valid permission names are foo1.bAr
, foo
, a.b.c
).The org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl
Kura service allows to persist the UserAdmin state in Kura configuration snapshot, this includes the defined identities and permissions.
The following configuration properties are used to store the UserAdmin concepts in Json format:
Stores the UserAdmin Roles, plain Roles are non used for representing Kura identities and permissions. The value must be a JSON array of Role elements.
Stores the UserAdmin Users. The value must be a JSON array of User elements.
Stores the UserAdmin Groups. The value must be a JSON array of Group elements.
"},{"location":"gateway-configuration/authentication-and-authorization/#json-representation-details","title":"JSON representation details","text":"This section describes the JSON format used in org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl
configuration.
A value appearing in UserAdmin dictionaries like properties and credentials
type : variant
Variants:
a String property
string
array
, element description: a byte of the array encoded as an unsigned integernumber
Examples:
\"A string property\"\n
[1, 2, 3, 4, 5]\n
"},{"location":"gateway-configuration/authentication-and-authorization/#useradmindict","title":"UserAdminDict","text":"A UserAdmin property dictionary, there are no well known property names, property values must be of UserAdminDictValue type
object
Example:
{\n \"stringProperty\": \"A string property\",\n \"byteArrayProperty\": [1, 2, 3, 4, 5]\n}\n
"},{"location":"gateway-configuration/authentication-and-authorization/#role","title":"Role","text":"An object describing and UserAdmin Role
type : object
Properties:
name The role name
type : string
properties
An object describing and UserAdmin User
type : object
Properties:
name The role name
type : string
properties
optional If the dictionary is empty
credentials
Example:
{\n \"name\": \"kura.user.appadmin\",\n \"credentials\": {\n \"kura.password\": \"3hPckF8Zc+IF3pVineBvck3zJERUl8itosySULE1hpM=\"\n }\n}\n
"},{"location":"gateway-configuration/authentication-and-authorization/#group","title":"Group","text":"An object describing and UserAdmin Group
type : object
Properties:
name The role name
type : string
properties
optional If the dictionary is empty
credentials
optional If the dictionary is empty
basicMembers
optional If the list is empty The list of the group basic members
array
, element description: A role namestring
requiredMembers
array
, element description: A role namestring
Example:
{\n \"name\": \"kura.permission.kura.wires.admin\",\n \"basicMembers\": [\"kura.user.appadmin\"]\n}\n
"},{"location":"gateway-configuration/cellular-configuration/","title":"Cellular Configuration","text":"If it is not configured, the cellular interface is presented on the interface list either by modem USB address, or if serial modem is used, by modem name. This 'fake' interface name is replaced by 'proper' interface name (e.g., ppp0) when the first modem configuration is submitted.
The cellular interface should be configured by first enabling it in the TCP/IP tab, and then setting the Cellular tab. Note that the cellular interface can only be set as WAN using DHCP. The cellular interface configuration options are described below.
"},{"location":"gateway-configuration/cellular-configuration/#cellular-configuration_1","title":"Cellular Configuration","text":"The Cellular tab contains the following configuration parameters:
Model: specifies the modem model.
Network Technology: describes the network technology used by this modem.
Modem Identifier: provides a unique name for this modem.
Interface #: provides a unique number for the modem interface (e.g., an interface # of 0 would name the modem interface ppp0).
Dial String: instructs how the modem should attempt to connect. Typical dial strings are as follows:
APN: defines the modem access point name.
This parameter is mandatory for standard profiles and optional for generic ones. In the case of generic profiles, if it is left empty, the value is automatically picked up from the Mobile Broadband Provider the modem is registered to. If a value is filled, the APN value is explicitly configured.
To avoid misconfiguration issues, it is strongly recommended to set it manually.
Note
APN value configuration
A good practice is to set the interface status to Disabled and then Enable For WAN when the APN is explicitly set. NetworkManager, indeed, will fallback to the default value if a wrong APN is specified, causing misleading behaviors. This does not happen if the interface is disabled and re-enabled after APN changes.
Auth Type: specifies the authentication type.
Username: supplies the username; disabled if no authentication method is specified.
Password: supplies the password; disabled if no authentication method is specified.
Modem Reset Timeout: sets the modem reset timeout in minutes. If set to a non-zero value, the modem is reset after n consecutive minutes of unsuccessful connection attempts. If set to zero, the modem keeps trying to establish a PPP connection without resetting. The default value is 5 minutes.
Reopen Connection on Termination: sets the persist option of the PPP daemon that specifies if PPP daemon should exit after connection is terminated. Note that the maxfail option still has an effect on persistent connections.
Connection Attempts Retry Delay: Sets the holdoff parameter to instruct the PPP daemon on how many seconds to wait before re-initiating the link after it terminates. This option only has any effect if the persist option (Reopen Connection on Termination) is set to true. The holdoff period is not applied if the link was terminated because it was idle. The default value is 1 second.
Connection Attempts: sets the maxfail option of the PPP daemon that limits the number of consecutive failed PPP connection attempts. The default value is 5 connection attempts. A value of zero means no limit. The PPP daemon terminates after the specified number of failed PPP connection attempts and restarts by the ModemMonitor thread.
Disconnect if Idle: sets the idle option of the PPP daemon, which terminates the PPP connection if the link is idle for a specified number of seconds. The default value is 95 seconds. To disable this option, set it to zero.
Active Filter: sets the active-filter option of the PPP daemon. This option specifies a packet filter (filter-expression) to be applied to data packets in order to determine which packets are regarded as link activity, and thereby, reset the idle timer. The filter-expression syntax is as described for tcpdump(1); however, qualifiers that do not apply to a PPP link, such as ether and arp, are not permitted. The default value is inbound. To disable the active-filter option, leave it blank.
LCP Echo Interval: sets the lcp-echo-interval option of the PPP daemon. If set to a positive number, the modem sends LCP echo request to the peer at the specified number of seconds. To disable this option, set it to zero. This option may be used with the lcp-echo-failure option to detect that the peer is no longer connected.
LCP Echo Failure: sets the lcp-echo-failure option of the PPP daemon. If set to a positive number, the modem presumes the peer to be dead if a specified number of LCP echo-requests are sent without receiving a valid LCP echo-reply. To disable this option, set it to zero.
The GPS tab allows the user to enable or disable the GPS module provided by the cellular modem. The available properties are:
UNMANAGED
: the GPS device of the modem will be setup but not directly managed, therefore freeing the serial port for other services to use. This can be used in order to perform the setup of the GPS and then have another service (like gpsd
) parse the NMEA strings in order to extract the position informations.MANAGED_GPS
: the GPS device of the modem will be setup and directly managed (typically by ModemManager) therefore the serial port won't be available for other services to use.GPS modes availability
GPS modes available for the modem are dependent on the modem model, modem firmware version and ModemManager version installed on the system. Some modes may not be selectable if the modem does not support them.
For \"device-specific profiles\" the GPS mode is not available and implicitly set to UNMANAGED
.
Therefore, to use the GPS module provided by the cellular modem with Kura's PositionService, the following considerations should be taken into account:
gpsd
and serial
PositionService providers with the GPS module provided by the cellular modem, the GPS mode should be set to UNMANAGED
.modemmanager
PositionService provider with the GPS module provided by the cellular modem, the GPS mode should be set to MANAGED_GPS
.Refer to the Position Service section for more information.
"},{"location":"gateway-configuration/cellular-configuration/#cellular-linux-configuration","title":"Cellular Linux Configuration","text":"This section describes the changes applied by Kura at the Linux networking configuration. Please read the following note before proceeding with manual changes of the Linux networking configuration.
Warning
It is NOT recommended performing manual editing of the Linux networking configuration files when the gateway configuration is being managed through Kura. While Linux may correctly accept manual changes, Kura may not be able to interpret the new configuration resulting in an inconsistent state.
When the cellular configuration is submitted, Kura generates peer and chat scripts used by the PPP daemon to establish a PPP connection. Examples of these scripts for HSPA and EVDO modems are shown below.
"},{"location":"gateway-configuration/cellular-configuration/#example-peer-script-for-hspa-modem","title":"Example Peer Script for HSPA Modem","text":"921600\nunit 0\nlogfile /var/log/HE910-D_2-1.5\ndebug\nconnect 'chat:v:f /etc/ppp/scripts/chat_HE910-D_2-1.5'\ndisconnect 'chat:v:f /etc/ppp/scripts/disconnect_HE910-D_2-1.5'\nmodem\nlock\nnoauth\nnoipdefault\ndefaultroute\nusepeerdns\nnoproxyarp\nnovj\nnovjccomp\nnobsdcomp\nnodeflate\nnomagic\nidle 95\nactive-filter 'inbound'\npersist\nholdoff 1\nmaxfail 5\nconnect-delay 1000\n
"},{"location":"gateway-configuration/cellular-configuration/#example-chat-script-for-hspa-modem","title":"Example Chat Script for HSPA Modem","text":"ABORT \"BUSY\"\nABORT \"VOICE\"\nABORT \"NO CARRIER\"\nABORT \"NO DIALTONE\"\nABORT \"NO DIAL TONE\"\nABORT \"ERROR\"\n\"\" \"+++ath\"\nOK \"AT\"\nOK AT+CGDCONT=1,\"IP\",\"c1.korem2m.com\"\nOK \"\\d\\d\\d\"\n\"\" \"atd-99---1#\"\nCONNECT \"\\c\"\n
"},{"location":"gateway-configuration/cellular-configuration/#example-peer-script-for-evdo-modem","title":"Example Peer Script for EVDO Modem","text":"921600\nunit 0\nlogfile /var/log/DE910-DUAL_1-1.5\ndebug\nconnect 'chat:v:f /etc/ppp/scripts/chat_DE910-DUAL_1-1.5'\ndisconnect 'chat:v:f /etc/ppp/scripts/disconnect_DE910-DUAL_1-1.5'\ncrtscts\nlock\nnoauth\ndefaultroute\nusepeerdns\nidle 95\nactive-filter 'inbound'\npersist\nholdoff 1\nmaxfail 5\nconnect-delay 10000\n
"},{"location":"gateway-configuration/cellular-configuration/#example-chat-script-for-evdo-modem","title":"Example Chat Script for EVDO Modem","text":"ABORT \"BUSY\"\nABORT \"VOICE\"\nABORT \"NO CARRIER\"\nABORT \"NO DIALTONE\"\nABORT \"NO DIAL TONE\"\nABORT \"ERROR\"\n\"\" \"+++ath\"\nOK \"AT\"\nOK \"ATE1V1&F&D2&C1&C2S0=0\"\nOK \"ATE1V1\"\nOK \"ATS7=60\"\nOK \"\\d\\d\\d\"\n\"\" \"atd#777\"\nCONNECT \"\\c\"\n
"},{"location":"gateway-configuration/cloud-connections/","title":"Cloud Connections","text":"The Cloud Connections section of the Kura Gateway Administration Console allows to create and manage cloud connections.
By default, Kura starts with a single cloud connection, as depicted in the following image:
The cloud services page allows to: - create a new cloud connection; - delete an existing cloud connection; - connect a selected cloud stack to the configured cloud platform; - disconnect the selected cloud stack from the connected cloud platform; - refresh the existing cloud connections.
When clicking on the New button, a dialog is displayed as depicted in the image below:
The user can select one of the existing cloud connection factories and give it a name (depending on the implementation, a name format can be suggested or forced).
Selecting a created Cloud Connection it is possible to associate a new publisher/subscriber by clicking the New Pub/Sub button. As for the connection creation case, the user can select one of the existing publisher/subscriber factories and give it a name.
"},{"location":"gateway-configuration/cloud-service-configuration/","title":"Cloud Service Configuration","text":"The CloudService provides an easy-to-use API layer for the M2M application to communicate with a remote server. It operates as a decorator for the DataService, providing add-on features over the management of the DataTransport layer.
In addition to simple publish/subscribe, the Cloud Connection API simplifies the implementation of more complex interaction flows like request/response or remote resource management. The Cloud Connection abstracts the developers from the complexity of the transport protocol and payload format used in the communication.
The Cloud Connection allows a single connection to a remote server to be shared across more than one application in the gateway, providing the necessary topic partitioning. Its functions include:
Adds application topic prefixes to allow a single remote server connection to be shared across applications.
Defines a payload data model and provides default encoding/decoding serializers.
Publishes life-cycle messages when the device and applications start and stop.
To use this service, select the CloudService option located in the Cloud Services area as shown in the screen capture below.
The CloudService provides the following configuration parameters:
device.display-name: defines the device display name given by the system. (Required field).
device.custom-name: defines the custom device display name if the device.display-name parameter is set to \"Custom\".
topic.control-prefix: defines the topic prefix used for system and device management messages.
encode.gzip: defines if the message payloads are sent compressed.
republish.mqtt.birth.cert.on.gps.lock: when set to true, forces a republish of the MQTT Birth Certificate when a GPS correct position lock is received. The device is then registered with its real coordinates. (Required field).
republish.mqtt.birth.cert.on.modem.detect: when set to true, forces a republish of the MQTT Birth Certificate when the service receives a modem detection event. This functionality is currently not supported on devices configured to use NetworkManager, in this case the property value is ignored. (Required field).
enable.default.subscriptions: manages the default subscriptions to the gateway management MQTT topics. When disabled, the gateway will not be remotely manageable.
payload.encoding: specifies the encoding for the messages sent by the specific CloudService instance.
{\n\"sentOn\" : 1491298822,\n\"position\" : {\n \"latitude\" : 45.234,\n \"longitude\" : -7.3456,\n \"altitude\" : 1.0,\n \"heading\" : 5.4,\n \"precision\" : 0.1,\n \"speed\" : 23.5,\n \"timestamp\" : 1191292288,\n \"satellites\" : 3,\n \"status\" : 2\n},\n\"metrics\": {\n \"code\" : \"A23D44567Q\",\n \"distance\" : 0.26456E+4,\n \"temperature\" : 27.5,\n \"count\" : 12354,\n \"timestamp\" : 23412334545,\n \"enable\" : true,\n \"rawBuffer\" : \"cGlwcG8gcGx1dG8gcGFwZXJpbm8=\"\n},\n\"body\": \"UGlwcG8sIHBsdXRvLCBwYXBlcmlubywgcXVpLCBxdW8gZSBxdWEu\"\n}\n
The default CloudService implementations publishes the following lifecycle messages:
The DataService provides the ability to connect to a remote broker, publish messages, subscribe to topics, receive messages on the subscribed topics, and disconnect from the remote message broker. The DataService delegates to the MqttDataTransport service the implementation of the transport protocol that is used to interact with the remote server.
The DataService also adds the capability of storing published messages in a persistent store function and sending them over the wire at a later time. The purpose of this feature is to relieve service users from implementing their own persistent store. Service users may publish messages independently on the DataService connection status.
Info
Starting from Kura 5.3.0, the DataService allows to bind to custom persistent stores. A custom persistent store can be defined by creating an implementation the new org.eclipse.kura.message.store.provider.MessageStoreProvider
service interface and registering it as an OSGi service.
In order to overcome the potential latencies introduced by buffering messages, the DataService allows a priority level to be assigned to\u200b each published message. Depending on the store configuration, there are certain guarantees that stored messages are not lost due to sudden crashes or power outages.
To use this service, select the DataService option located in the Cloud Connections area as shown in the screen capture below.
The DataService offers methods and configuration options to manage the connection to the remote server including the following (all required) parameters described below.
org.eclipse.kura.message.store.provider.MessageStoreProvider
interface.The DataService offers methods and configuration options to monitor the connection to the remote server and, eventually, cause a system reboot to recover from transient network problems.
This feature, if enabled, leverages the watchdog service and reboots the gateway if the maximum number of configured connection attempts has been made.
A reboot is not requested if the connection to the remote broker succeeds but an authentication error, an invalid client id or an authorization error is thrown by the remote cloud platform and causes a connection drop.
The image below shows the parameters that need to be tuned in order to enable this connection monitor feature.
To configure this functionality, the System Administrator needs to specify the following configuration elements:
Enable Recovery On Connection Failure: when enabled, activates the recovery feature on connection failure: if the device is not able to connect to a remote cloud platform, the service will wait for a specified amount of connection retries. If the recovery fails, the device will be rebooted. Being based on the Watchdog service, it needs to be activated as well.
Connection Recovery Max Failure: related to the previous parameter. It specifies the number of failures before a reboot is requested. !!! warning To be fully working, this feature needs the enabling of the Watchdog Service.
In order to have a finer control on the data flow, when a device reconnects to a remote cloud platform, Kura integrates into the Data Service a Backoff delay feature that limits the rate of messages sent.
This feature, enabled by default, integrates the Token Bucket concept to limit the bursts of messages sent to a remote cloud platform.
In the image below, the parameters that need to be tuned, in the Data Service, to take advantage of this feature:
Rate Limit Average - he average message publish rate in number of messages per unit of time (e.g. 10 messages per MINUTE).
Danger
The maximum allowed message rate is 1 message per millisecond, so the following limitations are applied:
The default setup limits the data flow to 1 message per second with a bucket size of 1 token.
Warning
This feature needs to be properly tuned by the System Administrator in order to prevent delays in the remote cloud platform due to messages stacked at the edge.
If not sure of the number of messages that your gateways will try to push to the remote platform, we suggest to disable this feature.
"},{"location":"gateway-configuration/data-service-configuration/#connection-schedule","title":"Connection schedule","text":"Starting from Kura 5.3.0, the Data Service supports a configurable time based connection schedule. If this functionality is enabled, the Data Service will connect at specific time instants represented by a configurable Cron expression, keep the connection open until it becomes idle and then disconnect until the next instant that matches the expression.
More in detail, the connection logic is as follows:
The DataService parses the confgiured Cron expression and schedules a connection attempt at the next instant that matches the expression. When the connection instant is reached, the logic continues from step 2.
The Data Service will start the auto connect logic. One or more connection attempts will be performed until the connection is established honoring the connect.retry-interval parameter.
The Data Service starts a timer that ticks after connection.schedule.inactivity.interval.seconds seconds. When the timer ticks the connection will be closed, and the logic resumed from step 1. The timer is reset delaying the disconnection when a message is published or confirmed (for QoS >= 1). The connection will not be closed if there are messages with QoS >= 1 that have not been confirmed yet. If an unexpected connection drop occurs in this phase, the logic will resume from step 2.
The Data Service will attempt to detect large time shifts in system clock, if a time shift is detected, the logic will switch to step 1, rescheduling the next connection attempt.
The relevant configuration parameters are the following:
Enable Connection Schedule: Enables or disables the connection schedule feature. Please note that in order to enable the connection logic, the Connect Auto-on-startup parameter must be set to true as well.
Connection Schedule CRON Expression: A CRON expression that specifies the instants when the gateway should perform a connection attempt. This parameter is only used if Enable Connection Schedule is set to true. The default expression schedules a connection every day at midnight.
Allow priority message to overide connection schedule - Allows messages beyond a specified priority to force a connection and be sent regardless of connection schedule.
Message schedule priority override threshold - A message with a priority equal to or less than this threshold will cause the framework to automatically re-connect and send regardless of the connection schedule.
Connection Schedule Disconnect Inactivity Interval Second: Specifies an inactivity timeout in seconds. If the timeout expires, the cloud connection will be automatically closed. This parameter is only used if Enable Connection Schedule is set to true.
Starting from Kura 5.3.0, the DataService allows to limit the maximum payload size for published messages. Attempts to publish a payload larger than the configured threshold will fail with a KuraStoreException. The threshold can be configured with the following parameter:
In order to keep backwards compatibility, the default value for the parameter is set to 16777216 bytes, which is the maximum allowed size by the current H2DbService implementation.
"},{"location":"gateway-configuration/data-transport-service-configuration/","title":"Data Transport Service Configuration","text":"The DataTransport service provides the ability to connect to a remote broker, publish messages, subscribe to topics, receive messages on the subscribed topics, and disconnect from the remote message broker. To use this service, select the MqttDataTransport option located in the Cloud Connections area as shown in the screen captures below.
The MqttDataTransport service provides the following configuration parameters:
broker-url: defines the URL of the MQTT broker to connect to. For the Everyware Cloud sandbox, this address is either mqtt://broker-sbx.everyware.io:1883/ or mqtts://broker-sbx.everyware.io:8883/ for an encrypted connection. (Required field).
topic.context.account-name: defines the name of the account to which the device belongs.
username and password: define the username and password that have been assigned to the device by the account administrator (generally username is account-name_broker). (Required field).
client-id: defines the identifier of the MQTT client representing the device when connecting to the MQTT broker. If left empty, it is automatically determined by the client software as the MAC address of the main network interface (in general numbers and uppercase letters without ':'). This identifier has to be unique within your account.
keep-alive: defines the \"keep alive\" interval measured in seconds. It specifies the maximum amount of time that should pass without communication between the client and the server. The client will ensure that at least one message travels across the network within each keep alive period. In the absence of a data-related message during this time period, the client will send a very small MQTT \"ping\" message that the server will acknowledge. The keep alive interval enables the client to detect when the server is no longer available without having to wait for the long TCP/IP timeout. (Required field).
Warning
The keep-alive interval may \"conflict\" with the TCP idle timeout set at the TCP/IP level. As a best practice the TCP idle timeout should be at least 1,5 times the keep-alive time interval. If the TCP idle timeout is less or equal the keep-alive, the MQTT connection may be dropped due to the TCP idle timeout expiration.
timeout: sets the timeout used for all interactions with the MQTT broker. (Required field).
clean-session: controls the behavior of both the client and the server at the time of connection and disconnection. When this parameter is set to true, the state information is discarded at connection and disconnection; when set to false, the state information is maintained. (Required field).
lwt parameters: define the MQTT \"Last Will and Testament\" (LWT) settings for the client. In the event that the client unexpectedly loses its connection to the server, the server publishes the LWT message (lwt.payload) to the LWT topic on behalf of the client. This allows other clients (subscribed to the LWT topic) to be made aware that the client has disconnected. LWT parameters that may be configured include:
in-flight.persistence: defines the storage type where in-flight messages are persisted across reconnections. They may be stored in memory, or in a file on the disk. (Required field).
protocol-version: defines the MQTT Protocol version to be used. This value may be 3.1 or 3.1.1.
SSL parameters: define the SSL specific settings for the client. SSL parameters that can be configured include:
The Device section provides several information about the gateway where Kura is running on. This section can be accessed by selecting the Device option located in the System area.
"},{"location":"gateway-configuration/device-information/#profile","title":"Profile","text":"The Profile tab shows several information about the gateway, organized under the Device, Hardware, Software and Java Information.
"},{"location":"gateway-configuration/device-information/#bundles","title":"Bundles","text":"This tab lists all the bundles installed on Kura, with details about the name, version, id, state and signature status. The signature value will be true if the corresponding bundle is signed, false otherwise.
The buttons in the upper part of the tab allows the user to manage the listed bundles:
The Containers tab lists the containers and images that are currently managed by the Container Orchestration Service. From this tab, the user can start and stop containers and delete images.
"},{"location":"gateway-configuration/device-information/#threads","title":"Threads","text":"The Threads tab shows a list of the threads that are currently running in the JVM.
"},{"location":"gateway-configuration/device-information/#system-packages","title":"System Packages","text":"The System Packages tab shows the list of all the Linux packages installed on the OS. The package is detailed with the name, version and type (DEB/RPM/APK).
"},{"location":"gateway-configuration/device-information/#system-properties","title":"System Properties","text":"The System Properties tab shows a list of relevant properties including OS and JVM parameters.
"},{"location":"gateway-configuration/device-information/#command","title":"Command","text":"A detailed description of this tab is presented in the Command Service page.
"},{"location":"gateway-configuration/device-information/#system-logs","title":"System Logs","text":"The System Logs tab allows downloading a compressed file containing all the relevant log files from the gateway. The download button creates and downloads a compressed file with the following items:
/var/log
or the content of the folder defined by the kura.log.download.sources property;kura-journal.log
);system-journal.log
).In addition to this feature, the page also allows the real-time displaying of system logs, if the framework has the availability of one or more components that implement the LogProvider API. The UI also provides a useful button to open a new Kura instance in a new browser window. A reference implementation of the LogProvider API is provided in the org.eclipse.kura.log.filesystem.provider
bundle. This bundle exposes in the framework a factory that can be used to read filesystem files. By default, Eclipse Kura creates two log providers at startup: one that reads from /var/log/kura.log
and the other that reads from /var/log/kura-audit.log
.
The collected logs are stored in a cache server-side and are collected from the point in time where the log providers get attached to the UI (usually, from the login or after a refresh of the browser's window). When the section \"System Logs\" is accessed, the new log entries are polled from the server's cache and stored client-side.
"},{"location":"gateway-configuration/ethernet-configuration/","title":"Ethernet Configuration","text":"As described in the Network Configuration section, Ethernet interfaces have two configuration tabs: TCP/IP and DHCP & NAT. Each Ethernet interface may be configured either as LAN or WAN; it may also be disabled.
If the interface is designated as LAN and is manually configured, the DHCP & NAT tab is enabled to allow DHCP server and/or 'many-to-one' NAT setup; otherwise, the DHCP & NAT tab is disabled.
For more information on TCP/IP and DHCP & NAT settings, please refer to the Network Configuration section.
"},{"location":"gateway-configuration/firewall-configuration/","title":"Firewall Configuration","text":"Kura offers easy management of the Linux firewall iptables and ip6tables included in an IoT Gateway. Additionally, Kura provides the ability to manage network access security to an IoT Gateway for both IPv4 and IPv6 through the following:
Open Ports, Port Forwarding, and IP Forwarding and Masquerading are configured via respective Firewall configuration tabs. 'Automatic' NAT is enabled for each local (LAN) interface using the DHCP & NAT tab of the respective interface configuration. While the IPv4 Firewall configuration capability is present on all IoT Gateways, the IPv6 Firewall is present only on devices that support IPv6 Networking.
"},{"location":"gateway-configuration/firewall-configuration/#firewall-linux-configuration","title":"Firewall Linux Configuration","text":"This section describes the changes applied by Kura at the Linux networking configuration. Please read the following note before proceeding with manual changes of the Linux networking configuration.
Warning
It is NOT recommended performing manual editing of the Linux networking configuration files when the gateway configuration is being managed through Kura. While Linux may correctly accept manual changes, Kura may not be able to interpret the new configuration resulting in an inconsistent state.
When a new firewall configuration is submitted, Kura immediately applies it using the iptables service provided by the OS. Moreover, the rules are stored in the filesystem and a new Kura snapshot is generated containing the new configuration. At the next startup, the firewall service in the OS will re-apply them and Kura will check the firewall configuration against the one contained in the last snapshot. In this way, the user can update the snapshot with the needed rules and apply them to the system using the webUI or modify the snapshot_0.xml
before the first start of Kura.
In order to allow a better coexistence between Kura and external applications that need to modify firewall rules, Kura writes its rules to a set of custom iptables chains. They are input-kura, output-kura, forward-kura, forward-kura-pf and forward-kura-ipf for the filter table and input-kura, output-kura, prerouting-kura, prerouting-kura-pf, postrouting-kura, postrouting-kura-pf and postrouting-kura-ipf for the nat table. The custom chains are then put in their respective standard iptables chains, as shown in the following:
iptables -t filter -I INPUT -j input-kura\niptables -t filter -I OUTPUT -j output-kura\niptables -t filter -I FORWARD -j forward-kura\niptables -t filter -I forward-kura -j forward-kura-pf\niptables -t filter -I forward-kura -j forward-kura-ipf\niptables -t nat -I PREROUTING -j prerouting-kura\niptables -t nat -I prerouting-kura -j prerouting-kura-pf\niptables -t nat -I INPUT -j input-kura\niptables -t nat -I OUTPUT -j output-kura\niptables -t nat -I POSTROUTING -j postrouting-kura\niptables -t nat -I postrouting-kura -j postrouting-kura-pf\niptables -t nat -I postrouting-kura -j postrouting-kura-ipf\n
The same custom chains are used in the IPv6 case.
Even if many firewall rules can be handled by Kura, it could be that some rules cannot be filled through the Web Console. In this case, custom firewall rules may be added to the /etc/init.d/firewall_cust script manually. These rules are applied/reapplied every time the firewall service starts, that is at the gateway startup. These custom rules should not be applied to the Kura custom chains, but to the standard ones.
"},{"location":"gateway-configuration/firewall-configuration/#open-ports","title":"Open Ports","text":"If Kura is running on a gateway, all TCP/UDP ports are closed by default unless they are listed in the Open Ports IPv4 or Open Ports IPv6 tab of the Firewall section in the Gateway Administration Console, or in the /etc/sysconfig/iptables
script. Therefore, if a user needs to connect to a specific port on a gateway, it is insufficient to have an application listening on the desired port; the port also needs to be opened in the firewall.
To open a port using the Gateway Administration Console, select the Firewall option located in the System area. The Firewall configuration display appears in the main window. With the Open Ports IPv4 or Open Ports IPV6 tab selected, click the New button. The New Open Port Entry form appears.
The New Open Port Entry form contains the following configuration parameters:
Complete the New Open Port Entry form and click the Submit button when finished. Once the form is submitted, a new port entry will appear. Click the Apply button for the change to take effect.
The firewall rules related to the open ports section are stored in the input-kura custom chain of the IPv4/IPv6 filter table.
"},{"location":"gateway-configuration/firewall-configuration/#port-forwarding","title":"Port Forwarding","text":"Port forwarding rules are needed to establish connectivity from the WAN side to a specific port on a host that resides on a LAN behind the gateway. In this case, a routing solution may be avoided since the connection is made to a specified external port on a gateway, and packets are forwarded to an internal port on the destination host; therefore, it is not necessary to add the external port to the list of open ports.
To add a port forwarding rule, select the Port Forwarding IPv4 or Port Forwarding IPv6 tab on the Firewall display and click the New button. The Port Forward Entry form appears.
The Port Forward Entry form contains the following configuration parameters:
Input Interface: specifies the interface through which a packet is going to be received. (Required field).
Output Interface: specifies the interface through which a packet is going to be forwarded to its destination. (Required field).
LAN Address: supplies the IP address of destination host. (Required field).
Protocol: defines the protocol (tcp or udp). (Required field).
External Port: provides the external destination port on gateway unit. (Required field).
Internal Port: provides the port on a destination host. (Required field).
Enable Masquerading: defines whether masquerading is used (yes or no). If enabled, the gateway replaces the IP address of the originating host with the IP address of its own output (LAN) interface. This is needed when the destination host does not have a back route to the originating host (or default gateway route) via the gateway unit. The masquerading option is provided with port forwarding to limit gateway forwarding only to the destination port. (Required field).
Permitted Network: only forwards if the packet is originated from a host on this network.
Permitted MAC Address: only forwards if the packet is originated by this host.
Source Port Range: only forwards if the packet's source port is within the defined range.
Complete the Port Forward Entry form and click the Apply button for the desired port forwarding rules to take effect.
The firewall rules related to the port forwarding section are stored in the forward-kura-pf custom chain of the IPv4/IPv6 filter table and in the postrouting-kura-pf and prerouting-kura-pf chains of the IPv4/IPv6 nat table.
"},{"location":"gateway-configuration/firewall-configuration/#port-forwarding-example","title":"Port Forwarding example","text":"This section describes an example of port forwarding rules applied to the IPv4 case. The initial setup is described below.
A couple of RaspberryPi that shares the same LAN over Ethernet.
The first RaspberryPi running Kura is configured as follows:
The second RaspberryPi running Kura is configured as follows:
A laptop is connected to the same network of the wlan0 of the second RaspberryPi and can ping its wlan0 interface.
The purpose of the second RaspberryPi configuration is to enable access to the Administration Console running on the first one (port 80) by connecting to the second RaspberryPi's port 8080 over the wlan. This scenario assumes that IP addresses are assigned as follows:
Second RaspberryPi wlan0 - 10.200.12.6
Laptop wlan0 - 10.200.12.10
The following port forwarding entries are added to the second RaspberryPi configuration as described above using the Port Forward Entry form:
Input Interface - wlan0
Output Interface - eth0
LAN Address - 172.16.0.5
Protocol - tcp
External Port - 8080
Internal Port - 80
Masquerade - yes
The Permitted Network, Permitted MAC Address, and Source Port Range fields are left blank.
The following iptables rules are applied and added to the /etc/sysconfig/iptables file:
iptables -t nat -A prerouting-kura-pf -i wlan0 -p tcp -s 0.0.0.0/0 --dport 8080 -j DNAT --to 172.16.0.5:80\niptables -t nat -A postrouting-kura-pf -o eth0 -p tcp -d 172.16.0.5 -j MASQUERADE\niptables -A forward-kura-pf -i wlan0 -o eth0 -p tcp -s 0.0.0.0/0 --dport 80 -d 172.16.0.5 -j ACCEPT\niptables -A forward-kura-pf -i eth0 -o wlan0 -p tcp -s 172.16.0.5 -m state --state RELATED,ESTABLISHED -j ACCEPT\n
The following iptables commands may be used to verify that the new rules have been applied:
sudo iptables -v -n -L\nsudo iptables -v -n -L -t nat\n
At this point, it is possible to try to connect to http://10.200.12.6 and to http://10.200.12.6:8080 from the laptop. Note that when a connection is made to the device on port 80, it is to the Kura configuration page on the device itself (the second RaspberryPi). When the gateway is connected on port 8080, you are forwarded to the Kura Gateway Administration Console on the first RaspberryPi. The destination host can only be reached by connecting to the gateway on port 8080.
Another way to connect to the Kura Gateway Administration Console on the first RaspberryPi would be to add an IP Forwarding/Masquerading entry as described in the next section.
"},{"location":"gateway-configuration/firewall-configuration/#ip-forwardingmasquerading","title":"IP Forwarding/Masquerading","text":"The advantage of the Automatic NAT method is its simplicity. However, this approach does not handle reverse NATing, and it cannot be used for interfaces that are not listed in the Gateway Administration Console (such as VPN tun0 interface). To set up generic (one-to-many) NATing, select the IP Forwarding/Masquerading IPv4 or IP Forwarding/Masquerading IPv6 tab on the Firewall display. Press the New button and the IP Forwarding/Masquerading form appears.
The IP Forwarding/Masquerading form contains the following configuration parameters:
Input Interface: specifies the interface through which a packet is going to be received. (Required field).
Output Interface: specifies the interface through which a packet is going to be forwarded to its destination. (Required field).
Protocol: defines the protocol of the rule to check (all, tcp, or udp). (Required field).
Source Network/Host: identifies the source network or host name (CIDR notation). Set to IPv4 0.0.0.0/0 or IPv6 ::/0 if empty.
Destination Network/Host: identifies the destination network or host name (CIDR notation). Set to IPv4 0.0.0.0/0 or IPv6 ::/0 if empty.
Enable Masquerading: defines whether masquerading is used (yes or no). If set to 'yes', masquerading is enabled. If set to 'no', only FORWARDING rules are be added. (Required field).
The rules will be added to the forward-kura-ipf chain in the IPv4/IPv6 filter table and in the postrouting-kura-ipf one in the IPv4/IPv6 nat table.
As a use-case scenario, consider the same setup as in port forwarding, but with cellular interface disabled and eth1 interface configured as WAN/DHCP client. In this case, the interfaces of the gateway are configured as follows:
eth0
: LAN/Static/No NAT 172.16.0.1/24
eth1
: WAN/DHCP 10.11.5.4/24
To reach the gateway sitting on the 172.16.0.5/24 from a specific host on the 10.11.0.0/16 network, set up the following Reverse NAT entry:
Input Interface: eth1 (WAN interface)
Output Interface: eth0 (LAN interface)
Protocol: all
Source Network/Host: 10.11.5.21/32
Destination Network/Host: 172.16.0.5/32
Enable Masquerading: yes
This case applies the following iptables rules:
iptables -t nat -A postrouting-kura-ipf -p tcp -s 10.11.5.21/32 -d 172.16.0.5/32 -o eth0 -j MASQUERADE\niptables -A forward-kura-ipf -p tcp -s 172.16.0.5/32 -i eth0 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT\niptables -A forward-kura-ipf -p tcp -s 10.11.5.21/32 -d 172.16.0.5/32 -i eth1 -o eth0 -m tcp -j ACCEPT\n
Additionally, a route to the 172.16.0.0/24 network needs to be configured on a connecting laptop as shown below:
sudo route add -net 172.16.0.0 netmask 255.255.255.0 gw 10.11.5.4\n
Since masquerading is enabled, there is no need to specify the back route on the destination host. Note that with this setup, the gateway only forwards packets originating on the 10.11.5.21 laptop to the 172.16.0.5 destination.
If the Source Network/Host and Destination Network/Host fields are empty, iptables rules appear as follows:
iptables -t nat -A postrouting-kura-ipf -p tcp -s 0.0.0.0/0 -d 0.0.0.0/0 -o eth0 -j MASQUERADE\niptables -A forward-kura-ipf -p tcp -s 0.0.0.0/0 -i eth0 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT\niptables -A forward-kura-ipf -p tcp -s 0.0.0.0/0 -d 0.0.0.0/0 -i eth1 -o eth0 -j ACCEPT\n
The gateway forwards packets from any external host (connected to eth1) to any destination on the local network (eth0 interface).
"},{"location":"gateway-configuration/gateway-administration-console-authentication/","title":"Gateway Administration Console Authentication","text":"The Gateway Administration Console supports multiple login identities with associated permissions and HTTPS client side authentication with certificates.
The identity and permission configuration and credentials is stored externally the UserAdmin service (see Authentication and Authorization for more details).
"},{"location":"gateway-configuration/gateway-administration-console-authentication/#permissions","title":"Permissions","text":"The Gateway Administration Console defines the following permissions, that allow to restrict the operations that an identity is allowed to perform:
Kura provides the following identities by default:
Name Password Permissions admin admin kura.admin appadmin appadmin kura.cloud.connection.admin, kura.packages.admin, kura.wires.admin netadmin netadmin kura.cloud.connection.admin, kura.device, kura.network.adminIt is possible to modify/remove the default identity configuration.
"},{"location":"gateway-configuration/gateway-administration-console-authentication/#login","title":"Login","text":"The login screen can be accessed by entering the https://${device.ip}
URL in a browser window, where ${device.ip}
is the IP address. Replace https
with http
if HTTPS support has been disabled on the gateway.
In order to login with identity name and password, select Password as authentication method and enter the credentials.
Note
Password authentication method might not be available if it has been disabled by the administrator using the Security -> Web Console section.
"},{"location":"gateway-configuration/gateway-administration-console-authentication/#forced-password-change-on-login","title":"Forced password change on login","text":"Kura supports forcing an identity to change the password at login, before accessing the Administration Console. This functionality is enabled by default after a fresh installation. At login the following prompt will appear forcing the user to define a new password.
This functionality can be configured by an admin identity using the Identities section of the Administration Console.
The forced password change can also be disabled by editing the snapshot_0.xml
file removing the kura.need.password.change
property for the desired identity in the org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl
configuration before Kura first boot. If this functionality is enabled, REST API username and password authentication is will be disabled for the specific identity until the password is updated, REST API certificate authentication will still work.
In order to perform HTTPS certificate authentication, select the Certificate authentication method and click Login, the browser may prompt to select the certificate to use.
Note
Certificate authentication method might not be available if no HTTPS with client authentication ports have been configured or if it has been explicitly disabled by the administrator using the Security -> Web Console section.
"},{"location":"gateway-configuration/gateway-administration-console-authentication/#identity-and-permission-management","title":"Identity and Permission management","text":"The Gateway Administration Console allows the management of identity and permission configuration in a dedicated view, accessible by navigating to the Identities section:
The section above allows to:
"},{"location":"gateway-configuration/gateway-administration-console-authentication/#create-new-identities","title":"Create new identities","text":"New identities can be created by clicking the New Identity button.
"},{"location":"gateway-configuration/gateway-administration-console-authentication/#remove-existing-identities","title":"Remove existing identities","text":"Existing identities can be removed by selecting the corresponding entry in the list and pressing the Delete Identity button.
"},{"location":"gateway-configuration/gateway-administration-console-authentication/#manage-password-authentication","title":"Manage password authentication","text":"Password authentication can be enabled or disabled by changing the Password authentication enabled parameter. Changing this parameter will not modify the existing stored password. Enabling password authentication for a new identity requires to define a new password. The password can be set/modified by clicking the Change password button.
"},{"location":"gateway-configuration/gateway-administration-console-authentication/#assign-or-remove-permissions","title":"Assign or remove permissions","text":"Permissions can be assigned or removed by ticking the corresponding entries in the Permissions table. No changes will be applied to the gateway until the Apply button is pressed.
"},{"location":"gateway-configuration/gateway-administration-console-authentication/#certificate-based-authentication","title":"Certificate based authentication","text":"The Gateway Administration Console supports HTTPS certificate based client side authentication. The authentication process works as follows:
One or more Https client certificate must be added to keystore, this can be done using the Certificate Management section.
The user must provide a certificate or certificate chain signed by one of the CAs added as Https client certificate.
The common name field of the leaf certificate provided by the user must be the name of the identity that should be used for the session.
HTTPS with certificate based authentication must be enabled in the HTTP/HTTPS Configuration section.
Log in with certificate can be performed by selecting the Certificate authentication method in Gateway Administration Console login screen or by connecting directly to the HTTPS port with client side authentication specified in gateway configuration.
"},{"location":"gateway-configuration/gateway-administration-console/","title":"Gateway Administration Console","text":""},{"location":"gateway-configuration/gateway-administration-console/#accessing-the-kura-gateway-administration-console","title":"Accessing the Kura Gateway Administration Console","text":"Kura provides a web-based, user interface for the administration and management of your IoT gateway. The Kura Gateway Administration Console enables you to monitor the gateway status, manage the network configuration, and manage the installed application and services. Access to the Kura Gateway Administration Console requires that a unit running Eclipse Kura is reachable via its Ethernet primary interface.
Connections on HTTP port 443 for these interfaces are allowed by default through the built-in firewall. The Kura Gateway Administration Console can be accessed by typing the IP address of the gateway into the browser's URL bar. Once the URL is submitted, the user is required to log in and is then redirected to the Administration Console (e.g., https://192.168.2.8/admin/console
) shown in the screen capture below. The default login name and password is admin/admin
.
Warning
It is recommended to change the default password after initial setup and before deployment, as well as limiting access to the Administration Console to a trusted local network interface using appropriate firewall rules.
"},{"location":"gateway-configuration/gateway-administration-console/#password-change","title":"Password change","text":"Once logged in, the user can modify its password (recommended after the first login). To access the option, click on the button near the username in the header section. A dropdown menu appears with the logout and the password modification options. When clicking on \"Change password\", the following dialog will appear:
After confirming the changes, the user will be logged out.
"},{"location":"gateway-configuration/gateway-administration-console/#accessing-the-kura-gateway-administration-console-over-a-cellular-link","title":"Accessing the Kura Gateway Administration Console over a Cellular Link","text":"In order to connect to the Gateway Administration Console via a cellular interface, the following requirements must be met:
If some of the used ports are blocked by the service provider, there is an option to reconfigure the gateway to use another port (i.e., 8080). In order to do so, the following requirements must be met:
Most browsers will probably warn the user that the connection is not secure when Gateway Administration Console is accessed using HTTPS.
In order to remove the warning, the browser must be able to verify the identity of the gateway as an HTTPS server. The verification process will fail with default server certificate provided by Kura because it is self-signed and it is not suitable for hostname verification.
Fixing this might require to configure the browser to trust the certificate provided by the gateway and/or using a server certificate signed by a CA trusted by the browser and assigning a DNS name to the gateway in order to pass hostname verification.
"},{"location":"gateway-configuration/gateway-administration-console/#system-use-notification-banner","title":"System Use Notification Banner","text":"For security reasons, it may be needed to display to the user a banner that describes the intended system use before authenticating. The system use notification message is customisable by authorised personnel in the Security section of the Kura Web UI, in the Web Console tab.
"},{"location":"gateway-configuration/gateway-status/","title":"Gateway Status","text":"The status of the gateway may be viewed from the Status window, which is accessed by selecting the Status option located in the System area. The Status window provides a summary of the key information regarding the status of the gateway including its IoT Cloud connection and network configuration.
The values reported in the page can be reloaded using the Refresh button. This will read the current values from the system and update the page. Since the update procedure can take time, the update can be performed at most every 30 seconds.
"},{"location":"gateway-configuration/gateway-status/#cloud-services","title":"Cloud Services","text":"This section provides a summary of the IoT Cloud connection status including the following details:
This section provides information about the currently configured network interfaces.
"},{"location":"gateway-configuration/gateway-status/#position-status","title":"Position Status","text":"This section provides the GPS status and latest known position (if applicable) including the following details:
Warning
The status reported in the page may not be synchronized with the real state of the system. In this case, use the Refresh button to updated the values in the page.
"},{"location":"gateway-configuration/keys-and-certificates/","title":"Keys and Certificates","text":"The framework manages directly different key pairs and trusted certificates from different keystores. To simplify the management of such complex objects, the framework provides a dedicated section of its Administrative Web UI, a set of REST APIs for local management and a request handler (KEYS-V1 and KEYS-V2) for cloud remote interaction.
"},{"location":"gateway-configuration/keys-and-certificates/#web-ui","title":"Web UI","text":"The Certificates List tab in the Security section of the Kura Web UI provides a simple way for the user to get the list of all the managed keys and certificates of the framework:
The page allows the user to add a new Keypair or trusted certificate or to delete an existing element.
Every key pair or trusted certificate is listed by its alias, identified by the corresponding type and further identified by the keystore that is managing that element.
If the user needs to add a new entry to one of the managed KeystoreService instances, can click on the Add button on the top left part of the page. The user will be guided through a process that will allow to identify the type of entry to add:
It can be either a:
If the user decides to add a key pair, then the wizard will provide a page like the following:
Here the user can specify: - Key Store: the KeystoreService instance that will store and maintain the key pair - Storage Alias: the alias that will be used to identify the key pair - Private Key: the private key part of the key pair - Certificate: the public key part of the key pair
After clicking on the Apply button, the new entry will be stored in the selected Keystore and listed along the other entries managed by the framework.
The following cryptographic algorithms are supported for Key Pairs: - RSA - DSA
Instead, if the user wants to load a Trusted Certificate, the Ui will change as follows:
Here the user can specify: - Key Store: the KeystoreService instance that will store and maintain the trusted certificate - Storage Alias: the alias that will be used to identify the trusted certificate - Certificate: the trusted certificate
The following cryptographic algorithms are supported for Trusted Certificates: - RSA - DSA - EC
"},{"location":"gateway-configuration/keys-and-certificates/#rest-apis","title":"REST APIs","text":""},{"location":"gateway-configuration/keys-and-certificates/#keystoresv1","title":"keystores/v1","text":"The org.eclipse.kura.core.keystore
bundle exposes a REST endpoint under the /services/keystores/v1
path. The Kura REST APIs for Keys and Certificates support the following calls and are allowed to any user with rest.keystores
permission.
/
keystores JSON None Returns the list of all the KeystoreService instances. GET /entries
keystores JSON None Returns the list of all the entries managed by the KeystoreService instances. GET /entries?keystoreServicePid={keystoreServicePid}
keystores JSON keystoreServicePid Returns the list of all the entries managed by the specified KeystoreService instance. GET /entries?alias={alias}
keystores JSON alias Returns the list of all the entries specified by the defined alias and managed in all the available KeystoreService instances in the framework. GET /entries/entry?keystoreServicePid={keystoreServicePid}&alias={alias}
keystores JSON keystoreServicePid and alias Returns the entry identified by the specified keystoreServicePid and alias. POST /entries/csr
keystores JSON The reference to the key pair in a specified KeystoreService instance that will be used to generate the CSR. The request has to be associated with additional parameters that identify the algorithm used to compute and sign the CSR and the DN or the corresponding public key that needs to be countersigned. Generates a CSR for the specified key pair in the specified KeystoreService instance, based on the parameters provided in the request. POST /entries/certificate
keystores JSON The reference to the KeystoreService instance and the alias that will be used for storage. A type filed identifies the type of key that needs to be managed. This request allows the user to upload a TrustedCertificate. POST /entries/keypair
keystores JSON To generate a new KeyPair directly in the device, the request format need to follow the references in the following paragraphs. This request allows the user to generate a new KeyPair into the device. DELETE /entries
keystores JSON A JSON identifying the resource to delete. The format of the request is described in in one of the following sections. Deletes the entry in the specified KeystoreService instance."},{"location":"gateway-configuration/keys-and-certificates/#list-all-the-keystoreservices","title":"List All the KeystoreServices","text":"Request: URL - https://<gateway-ip>/services/keystores/v1
Response:
[\n {\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.SSLKeystore\",\n \"type\": \"jks\",\n \"size\": 4\n },\n {\n \"keystoreServicePid\": \"org.eclipse.kura.crypto.CryptoService\",\n \"type\": \"jks\",\n \"size\": 3\n },\n {\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.HttpsKeystore\",\n \"type\": \"jks\",\n \"size\": 1\n },\n {\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.DMKeystore\",\n \"type\": \"jks\",\n \"size\": 1\n }\n]\n
"},{"location":"gateway-configuration/keys-and-certificates/#get-all-the-managed-entries","title":"Get all the Managed Entries","text":"Request: URL - https://<gateway-ip>/services/keystores/v1/entries
Response:
[\n {\n \"subjectDN\": \"OU=Go Daddy Class 2 Certification Authority, O=\\\"The Go Daddy Group, Inc.\\\", C=US\",\n \"issuer\": \"OU=Go Daddy Class 2 Certification Authority,O=The Go Daddy Group\\\\, Inc.,C=US\",\n \"startDate\": \"Tue, 29 Jun 2004 17:06:20 GMT\",\n \"expirationDate\": \"Thu, 29 Jun 2034 17:06:20 GMT\",\n \"algorithm\": \"SHA1withRSA\",\n \"size\": 2048,\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.SSLKeystore\",\n \"alias\": \"ca-godaddyclass2ca\",\n \"type\": \"TRUSTED_CERTIFICATE\"\n },\n {\n \"algorithm\": \"RSA\",\n \"size\": 4096,\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.HttpsKeystore\",\n \"alias\": \"localhost\",\n \"type\": \"PRIVATE_KEY\"\n }\n]\n
"},{"location":"gateway-configuration/keys-and-certificates/#get-all-the-entries-by-keystoreservice","title":"Get All the Entries by KeystoreService","text":"Request: URL - https://<gateway-ip>/services/keystores/v1/entries?keystoreServicePid=org.eclipse.kura.core.keystore.HttpsKeystore
Response:
[\n {\n \"algorithm\": \"RSA\",\n \"size\": 4096,\n \"certificateChain\": [\n \"-----BEGIN CERTIFICATE-----\\n<CERTIFICATE>\\n-----END CERTIFICATE-----\"\n ],\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.HttpsKeystore\",\n \"alias\": \"localhost\",\n \"type\": \"PRIVATE_KEY\"\n }\n]\n
"},{"location":"gateway-configuration/keys-and-certificates/#get-all-the-entries-by-alias","title":"Get All the Entries by Alias","text":"Request: URL - https://<gateway-ip>/services/keystores/v1/entries?alias=localhost
Response:
[\n {\n \"algorithm\": \"RSA\",\n \"size\": 4096,\n \"certificateChain\": [\n \"-----BEGIN CERTIFICATE-----\\n<CERTIFICATE>\\n-----END CERTIFICATE-----\"\n ],\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.HttpsKeystore\",\n \"alias\": \"localhost\",\n \"type\": \"PRIVATE_KEY\"\n }\n]\n
"},{"location":"gateway-configuration/keys-and-certificates/#get-specific-entry","title":"Get Specific Entry","text":"Request: URL - https://<gateway-ip>/services/keystores/v1/entries/entry?keystoreServicePid=org.eclipse.kura.core.keystore.HttpsKeystore&alias=localhost
Response:
{\n \"algorithm\": \"RSA\",\n \"size\": 4096,\n \"certificateChain\": [\n \"-----BEGIN CERTIFICATE-----\\n<CERTIFICATE>-----END CERTIFICATE-----\"\n ],\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.HttpsKeystore\",\n \"alias\": \"localhost\",\n \"type\": \"PRIVATE_KEY\"\n}\n
"},{"location":"gateway-configuration/keys-and-certificates/#get-the-csr-for-a-keypair","title":"Get the CSR for a KeyPair","text":"Request: URL - https://<gateway-ip>/services/keystores/v1/entries/csr
keystoreServicePid=org.eclipse.kura.core.keystore.HttpsKeystore&alias=localhost`
Request body:
{ \n \"keystoreServicePid\":\"org.eclipse.kura.core.keystore.HttpsKeystore\",\n \"alias\":\"localhost\",\n \"signatureAlgorithm\" : \"SHA256withRSA\",\n \"attributes\" : \"CN=Kura, OU=IoT, O=Eclipse, C=US\"\n}\n
"},{"location":"gateway-configuration/keys-and-certificates/#store-trusted-certificate","title":"Store Trusted Certificate","text":"Request: URL - https://<gateway-ip>/services/keystores/v1/entries/certificate
Request body:
{\n \"keystoreServicePid\":\"MyKeystore\",\n \"alias\":\"myCertTest99\",\n \"certificate\":\"-----BEGIN CERTIFICATE-----\n <CERTIFICATE>\n -----END CERTIFICATE-----\"\n}\n
"},{"location":"gateway-configuration/keys-and-certificates/#generate-keypair","title":"Generate KeyPair","text":"Request: URL - https://<gateway-ip>/services/keystores/v1/entries/keypair
Request body:
{\n \"keystoreServicePid\":\"MyKeystore\",\n \"alias\":\"keypair1\",\n \"algorithm\" : \"RSA\",\n \"size\": 1024,\n \"signatureAlgorithm\" : \"SHA256WithRSA\",\n \"attributes\" : \"CN=Kura, OU=IoT, O=Eclipse, C=US\"\n}\n
"},{"location":"gateway-configuration/keys-and-certificates/#delete-entry","title":"Delete Entry","text":"Request: URL - https://<gateway-ip>/services/keystores/v1/entries
Request body:
{\n \"keystoreServicePid\" : \"MyKeystore\",\n \"alias\" : \"mycerttestec\"\n}\n
"},{"location":"gateway-configuration/keys-and-certificates/#keys-v1-request-handler","title":"KEYS-V1 Request Handler","text":"Mapping the previously defined REST APIs, the framework exposed to the remote cloud platforms a request handler named KEYS-V1 that allows the remote user to list and manage the keystores, the keys and the certificates in the framework.
The request handler exposes also the capability to generate on the edge a CSR that can be countersigned remotely by a trusted CA.
"},{"location":"gateway-configuration/keys-and-certificates/#keystoresv2","title":"keystores/v2","text":"Starting from Kura 5.4.0, the keystores/v2
REST API is also available, it supports all of the request endpoints of keystores/v1
plus an additional endpoint that allows to upload and modify private key entries:
/entries/privatekey
keystores JSON To upload a new private key entry directly in the device, the request format need to follow the references in the following paragraphs. This request allows the user to upload a new private key entry into the device or to modify the certificate chain of an existing one."},{"location":"gateway-configuration/keys-and-certificates/#uploading-a-private-key-entry","title":"Uploading a Private Key Entry","text":"Request: URL - https://<gateway-ip>/services/keystores/v2/entries/privatekey
Request body:
The request should include the private key in unencrypted PEM format and the certificate chain in PEM format, the first certificate in the certificateChain
list must use the public key associated with the private key supplied as the privateKey
parameter.
The device will overwrite the entry with the provided alias if it already exists.
WARINING: Please use this endpoint through a secure connection.
{\n \"keystoreServicePid\":\"MyKeystore\",\n \"alias\":\"keypair1\",\n \"privateKey\":\"-----BEGIN RSA PRIVATE KEY-----\\n...\\n-----END RSA PRIVATE KEY-----\",\n \"certificateChain\":[\n \"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\",\n \"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\",\n ]\n}\n
"},{"location":"gateway-configuration/keys-and-certificates/#updating-a-private-key-entry","title":"Updating a Private Key Entry","text":"Request: URL - https://<gateway-ip>/services/keystores/v2/entries/privatekey
Request body:
In order to update the certificate chain associated to a specific private key entry it is possible to use the same format as previous request and omit the privateKey
parameter.
In this case the certificate chain of the existing entry will be replaced with the one specified in the request and the existing private key will be retained.
This request can be useful for example to create a CSR on the device, sign it externally and then updating the corresponding entry with the resulting certificate.
{\n \"keystoreServicePid\":\"MyKeystore\",\n \"alias\":\"keypair1\",\n \"certificateChain\":[\n \"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\",\n \"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\",\n ]\n}\n
"},{"location":"gateway-configuration/keystores-management/","title":"Keystores Management","text":"The framework manages different types of cryptographic keys and certificates. In order to simplify the interaction with those objects, Kura provides a KeystoreService API and a specific section in the Kura Web UI that lists all the available KeystoreService instances.
From the Security section, a user with Security permissions can access the Keystore Configuration section. A list of all the framework managed keystores will be available to the user with the Service PID that will be used by other components to reference the selected keystore. Associated to the Service PID, the UI shows the Factory PID that identifies the specific KeystoreService API implementation that is providing the service to the framework.
In order to modify the configuration of a specific keystore service instance, the user can select one of the available rows, obtaining the corresponding keystore service configuration.
The following KeystoreService factories are available:
"},{"location":"gateway-configuration/keystores-management/#filesystemkeystoreserviceimpl","title":"FilesystemKeystoreServiceImpl","text":"The org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl
factory provides a KeystoreService implementation that stores the private keys and certificates as a file. The user can customise the following options:
The org.eclipse.kura.core.keystore.PKCS11KeystoreServiceImpl
factory provides a KeystoreService implementation that allows to access a PKCS11 token through the SunPKCS11 implementation.
At the moment this type of KeystoreService provides read only access to the underlying token, operations such as adding or removing entries will fail.
It is possible to use the entries provided by a PKCS11KeystoreServiceImpl
for SSL authentication.
The available configuration options closely match the parameters provided by the SunPKCS11 implementation, see the official documentation for more details.
In particular, the official documentation contains a section that explains how the PKCS11 objects are mapped to Java KeyStore entries.
The only required parameter is the PKCS11 Implementation Library Path parameter. It is usually also necessary to specify the token user pin as the Pin parameter.
The configuration parameters are mapped to the SunPKCS11 provider parameters in the following way:
Kura Parameter SunPKCS11 Parameter Notes Slot slot Slot List Index slotListIndex Enabled Mechanisms enabledMechanisms The curly braces must be omitted Disabled Mechanisms disabledMechanisms The curly braces must be omitted. Attributes attributes The value of this field will be appended to the provider configuration."},{"location":"gateway-configuration/network-advanced/","title":"Advanced Network Settings","text":"For devices running Kura installed using a Generic Profile, it is possible to to fine tune network traffic settings. Take a look at our installer profiles to know which are supported.
The Advanced configuration tab is designed for users who seek a higher level of control and customization over their network experience. Whether you are an IT professional, network administrator, or enthusiast looking to fine-tune specific aspects of your network, this tab provides access to advanced parameters like Maximum Transmission Unit (MTU) and Promiscuous Mode. Adjusting these settings allows for optimized performance in unique network environments, troubleshooting capabilities, and enhanced security monitoring. Please exercise caution when modifying these settings, ensuring that you have a clear understanding of their implications on your network's behavior.
Tip
Some parameters requires a minimum version of NetworkManager, as described below and in Kura UI. The System Component Inventory can be used to check what version is available on your device.
The Advanced tab allow configuration of:
The Advanced tab contains the following configuration parameters:
Warning
The MTU value for a VLAN is limited by the configured MTU of its parent interface as an upper bound.
To configure the gateway network interfaces using the Gateway Administration Console, select the Network option located in the System area. With this option selected, the Network display appears with a list of available interfaces. Configuration tabs for the selected interface appear on the right side of the screen. By default, the loopback (lo) interface is selected when the network interfaces are displayed. Choose the desired network interface (e.g., eth0, eth1, wlan0, ppp0) and apply the necessary configuration changes using the tabs on the right. Submit the modified configuration by clicking the Apply button.
In case of typing errors, the Reset button can be used to reload the prior configuration on the screen. Since the network configuration shown on the screen may not be synchronized with the current state of the system, it can be updated pressing the Refresh button. This can be used also to force the reload of specific parameters like the RSSI or dynamic IP addresses. The refresh procedure reads all the needed parameters from the system and can take several seconds before updating.
Tip
It is recommended that the TCP/IP tab is configured first since it defines how the interface is going to be used.
"},{"location":"gateway-configuration/network-configuration/#tcpip-configuration","title":"TCP/IP Configuration","text":"The TCP/IP tab contains the following configuration parameters:
If the network interface is Enabled for LAN and manually configured (i.e., not a DHCP client), the DHCP & NAT tab allows the DHCP server to be configured and/or NAT (IP forwarding with masquerading) to be enabled.
"},{"location":"gateway-configuration/network-configuration/#more-details-about-the-not-managed-interface-status","title":"More details about the Not Managed interface Status","text":"When a network interface is configured as Not Managed, Kura will ignore it and the configuration will not be touched. The user can configure the interface with the network tools provided by the OS, allowing unusual network setups.
Regarding DNS, both Kura and the external tools store the DNS addresses in the /etc/resolv.conf
file. So, if multiple interfaces are configured to get the DNS information and store it in the same file, the device can be misconfigured. To avoid that, the following table presents who is responsible to update the DNS file depending on the network interfaces configurations.
WAN
? Is there at least one interface set as Not Managed
? Does Kura manage resolv.conf? NO NO YES NO YES NO YES NO YES YES YES YES So, the only way to configure the DNS addresses with external tools, is to configure at least one interface as Not Managed and not to set any interface as Enabled For Wan using Kura. If at least one WAN interface is configured by Kura, it will take the control of the /etc/resolv.conf/
file. Finally, if any interface is configured in Enabled For Wan or Not Managed mode, Kura will empty the file.
To avoid device misconfigurations when Not Managed interfaces are used, don't use the dns-nameservers directive in the /etc/network/interfaces
file. Please add the DNS addresses directly to the /etc/resolv.conf
file.
The DHCP & NAT tab contains the following configuration parameters:
If NAT is enabled and there is another interface designated as WAN (e.g., ppp0), the following iptables rules are added to the custom automatic NAT service rules_* section of the /etc/init.d/firewall
script:
# custom automatic NAT service rules (if NAT option is enabled for LAN interface)\niptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE\niptables -A FORWARD -i ppp0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT\niptables -A FORWARD -i eth0 -o ppp0 -j ACCEPT\n
Also, IP forwarding is enabled in the kernel as follows:
# allow fowarding if any masquerade is defined\necho 1 > /proc/sys/net/ipv4/ip_forward\n
The rules shown above create an Overloaded_ (i.e., many-to-one) NAT. This type of network address translation maps multiple IP addresses on the LAN side to a single IP address on the WAN side, allowing internet access from hosts on a local network via a gateway (WAN) interface. Note that for NAT rules to be added, it is insufficient to enable NATing through the DHCP & NAT* tab of the LAN interface; there must also be another interface designated as WAN.
"},{"location":"gateway-configuration/network-configuration/#network-linux-configuration","title":"Network Linux Configuration","text":"When applying a new network configuration, Kura changes the configuration files of the Linux networking subsystem. Please read the following note before proceeding with manual changes of the Linux networking configuration.
Warning
It is NOT recommended performing manual editing of the Linux networking configuration files when the gateway configuration is being managed through Kura. While Linux may correctly accept manual changes, Kura may not be able to interpret the new configuration resulting in an inconsistent state.
"},{"location":"gateway-configuration/network-configuration/#network-configuration-properties","title":"Network Configuration properties","text":"The Network configuration can be modified using the Kura Gateway Administration Console, as described above, the Configuration Service or appling a proper snapshot.
The following table describes all the properties related to the Network Configuration. It includes the name of the property, the type, a description and the default value (if applicable). The network configuration pid is org.eclipse.kura.net.admin.NetworkConfigurationService
.
net.interfaces
String Comma-separated list of the interface names in the device net.interface.<interface>.type
String The type of the network interface; possible values are: ETHERNET
, WIFI
, MODEM
, VLAN
, LOOPBACK
and UNKNOWN
UNKNOWN
net.interface.<interface>.config.wifi.mode
String For wifi interfaces, specify the modality; possible values are INFRA
, MASTER
and UNKNOWN
UNKNOWN
net.interface.<interface>.config.nat.enabled
Boolean Enable the NAT feature false net.interface.<interface>.config.promisc
Integer Enable the Promiscuous Mode; possible values are: -1 (System default), 0 (Disabled), 1 (Enabled) -1"},{"location":"gateway-configuration/network-configuration/#ipv4-properties","title":"IPv4 properties","text":"Name Type Description Default value net.interface.<interface>.config.ip4.status
String The status of the interface for the IPv4 configuration; possibile values are: netIPv4StatusDisabled
, netIPv4StatusUnmanaged
, netIPv4StatusL2Only
, netIPv4StatusEnabledLAN
, netIPv4StatusEnabledWAN
, netIPv4StatusUnknown
netIPv4StatusDisabled
(see note below) net.interface.<interface>.config.ip4.wan.priority
Integer (NetworkManager only) Priority used to determine which interface select as primary WAN. Allowed values range from -1 to 2147483647, inclusive. See Network Failover for further details -1 net.interface.<interface>.config.ip4.address
String The IPv4 address assigned to the network interface net.interface.<interface>.config.ip4.prefix
Short The IPv4 netmask assigned to the network interface -1 net.interface.<interface>.config.ip4.gateway
String The IPv4 address of the default gateway net.interface.<interface>.config.ip4.dnsServers
String Comma-separated list of dns servers net.interface.<interface>.config.ip4.mtu
Integer The Maximum Transition Unit (MTU) for this interface Note
For physical interfaces the default status is netIPv4StatusDisabled
. For virtual ones, instead, the default status is defined by the kura.net.virtual.devices.config
property in the kura.properties
file.
net.interface.<interface>.config.dhcpServer4.enabled
Boolean Specify if the DHCP server is enabled false net.interface.<interface>.config.dhcpServer4.rangeStart
String First IP address available for clients net.interface.<interface>.config.dhcpServer4.rangeEnd
String Last IP address available for clients net.interface.<interface>.config.dhcpServer4.defaultLeaseTime
Integer The default lease time -1 net.interface.<interface>.config.dhcpServer4.maxLeaseTime
Integer The maximum lease time -1 net.interface.<interface>.config.dhcpServer4.prefix
Short The netmask for the available IP addresses -1 net.interface.<interface>.config.dhcpServer4.passDns
Boolean Specify if the DNS server addresses has to be passed through DHCP false"},{"location":"gateway-configuration/network-configuration/#ipv4-dhcp-client-properties","title":"IPv4 DHCP Client properties","text":"Name Type Description Default value net.interface.<interface>.config.dhcpClient4.enabled
Boolean Specify if the DHCP client is enabled false"},{"location":"gateway-configuration/network-configuration/#ipv6-properties","title":"IPv6 properties","text":"Name Type Description Default value net.interface.<interface>.config.ip6.status
String The status of the interface for the IPv6 configuration; possibile values are: netIPv6StatusDisabled
, netIPv6StatusUnmanaged
, netIPv6StatusL2Only
, netIPv6StatusEnabledLAN
, netIPv6StatusEnabledWAN
, netIPv6StatusUnknown
netIPv6StatusDisabled
(see note below) net.interface.<interface>.config.ip6.wan.priority
Integer (NetworkManager only) Priority used to determine which interface select as primary WAN. Allowed values range from -1 to 2147483647, inclusive. See Network Failover for further details -1 net.interface.<interface>.config.ip6.address.method
String The IPv6 configuration method; possible values are: AUTO
, DHCP
, MANUAL
. AUTO
net.interface.<interface>.config.ip6.address
String The IPv6 address assigned to the network interface net.interface.<interface>.config.ip6.prefix
Short The IPv6 netmask assigned to the network interface -1 net.interface.<interface>.config.ip6.gateway
String The IPv6 address of the default gateway net.interface.<interface>.config.ip6.dnsServers
String Comma-separated list of dns servers net.interface.<interface>.config.ip6.addr.gen.mode
String The IPv6 address generation mode; possible values are EUI64
, STABLE_PRIVACY
net.interface.<interface>.config.ip6.privacy
String The IPv6 Privacy Extensions for SLAAC; possible values are DISABLED
, ENABLED_PUBLIC_ADD
, ENABLED_TEMP_ADD
net.interface.<interface>.config.ip6.mtu
Integer The Maximum Transition Unit (MTU) for Ipv6 traffic on this interface. Requires NetworkManager 1.40 or newer Note
For physical interfaces the default status is netIPv6StatusDisabled
. For virtual ones, instead, the default status is defined by the kura.net.virtual.devices.config
property in the kura.properties
file.
net.interface.<interface>.config.wifi.master.driver
String The driver used for the connection net.interface.<interface>.config.wifi.master.passphrase
Password The password for the access point net.interface.<interface>.config.wifi.master.ssid
String The SSID of the access point net.interface.<interface>.config.wifi.master.securityType
String The security protocol for the wireless network; possible values are SECURITY_NONE
, SECURITY_WEP
, SECURITY_WPA
, SECURITY_WPA2
, SECURITY_WPA_WPA2
SECURITY_NONE
net.interface.<interface>.config.wifi.master.mode
String The mode of the wireless connection; for the access point mode set it to MASTER
MASTER
net.interface.<interface>.config.wifi.master.channel
String The channel to be used for the access point 1 net.interface.<interface>.config.wifi.master.radioMode
String Specify the 802.11 radio mode; possible values are RADIO_MODE_80211a
, RADIO_MODE_80211b
, RADIO_MODE_80211g
, RADIO_MODE_80211nHT20
, RADIO_MODE_80211_AC
RADIO_MODE_80211b
net.interface.<interface>.config.wifi.master.ignoreSSID
Boolean Specify if the SSID broadcast is ignored false net.interface.<interface>.config.wifi.master.groupCiphers
String Group ciphers i.e. group/broadcast encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms set, possible values are CCMP
, TKIP
, and CCMP_TKIP
CCMP_TKIP
net.interface.<interface>.config.wifi.master.pairwiseCiphers
String Pairwise ciphers i.e. pairwise encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms set, possible values are CCMP
, TKIP
, and CCMP_TKIP
CCMP_TKIP
"},{"location":"gateway-configuration/network-configuration/#wifi-infra-station-mode-properties","title":"WiFi Infra (Station Mode) properties","text":"Name Type Description Default value net.interface.<interface>.config.wifi.infra.ssid
String The SSID of the wireless network to connect to net.interface.<interface>.config.wifi.infra.channel
String The channel of the wireless network to connect to 1 net.interface.<interface>.config.wifi.infra.bgscan
String Set the background scans; possible values have the form <mode>:<shortInterval>:<rssiThreshold>:<longInterval>
where mode
(String) is one of NONE, SIMPLE, or LEARN, shortInterval
(Integer) sets the Bgscan short interval (secs), rssiThreshold
(Integer) sets the Bgscan Signal strength threshold (dBm), and longInterval
(Integer) sets the Bgscan long interval (secs) net.interface.<interface>.config.wifi.infra.passphrase
Password The password for the wireless network net.interface.<interface>.config.wifi.infra.ignoreSSID
Boolean Specify if a scan for SSID is required before attempting to associate false net.interface.<interface>.config.wifi.infra.mode
String The mode of the wireless connection; for station mode set to INFRA
INFRA
net.interface.<interface>.config.wifi.infra.pingAccessPoint
Boolean Enable pinging the access point after connection is established false net.interface.<interface>.config.wifi.infra.driver
String The driver used for the connection net.interface.<interface>.config.wifi.infra.securityType
String The security protocol for the wireless network; possible values are SECURITY_NONE
, SECURITY_WEP
, SECURITY_WPA
, SECURITY_WPA2
, SECURITY_WPA_WPA2
SECURITY_NONE
net.interface.<interface>.config.wifi.infra.groupCiphers
String Group ciphers i.e. group/broadcast encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms set, possible values are CCMP
, TKIP
, and CCMP_TKIP
CCMP_TKIP
net.interface.<interface>.config.wifi.infra.pairwiseCiphers
String Pairwise ciphers i.e. pairwise encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms set, possible values are CCMP
, TKIP
, and CCMP_TKIP
CCMP_TKIP
"},{"location":"gateway-configuration/network-configuration/#cellular-modem-properties","title":"Cellular Modem properties","text":"Name Type Description Default value net.interface.<interface>.config.enabled
Boolean Enable the interface false net.interface.<interface>.config.idle
Integer The idle option of the PPP daemon 95 net.interface.<interface>.config.username
String The username used for the connection net.interface.<interface>.config.password
Password The password used for the connection net.interface.<interface>.config.pdpType
String The PdP type; possible values are IP, PPP and IPv6 IP net.interface.<interface>.config.maxFail
Integer The maxfail option of the PPP daemon 5 net.interface.<interface>.config.authType
String The authentication type; possible values are NONE
, AUTO
, CHAP
and PAP
NONE
net.interface.<interface>.config.lpcEchoInterval
Integer The lcp-echo-interval option of the PPP daemon 0 net.interface.<interface>.config.activeFilter
String The active-filter option of the PPP daemon inbound net.interface.<interface>.config.lpcEchoFailure
Integer The lcp-echo-failure option of the PPP daemon 0 net.interface.<interface>.config.diversityEnabled
Boolean Enable the LTE diversity antenna false net.interface.<interface>.config.resetTimeout
Integer The modem reset timeout in minutes 5 net.interface.<interface>.config.gpsEnabled
Boolean Enable the GPS device in the modem if available false net.interface.<interface>.config.gpsMode
String Select the GPS mode to activate for the modem if available kuraModemGpsModeUnmanaged
net.interface.<interface>.config.persist
Boolean The persist option of the PPP daemon true net.interface.<interface>.config.apn
String The modem Access Point Name net.interface.<interface>.config.dialString
String The dial string used for connecting to the APN net.interface.<interface>.config.holdoff
Integer The holdoff option of the PPP daemon (in seconds) 1 net.interface.<interface>.config.pppNum
Integer Assigned ppp interface number 0"},{"location":"gateway-configuration/network-configuration/#gps-mode","title":"GPS Mode","text":"The GPS mode can be set to one of the following values:
kuraModemGpsModeUnmanaged
: the GPS device of the modem will be setup but not directly managed, therefore freeing the serial port for other services to use. This can be used in order to perform the setup of the GPS and then have another service (like gpsd
) parse the NMEA strings in order to extract the position informations. This is the default value.kuraModemGpsModeManagedGps
: the GPS device of the modem will be setup and directly managed (typically by ModemManager) therefore the serial port won't be available for other services to use.For older versions compatibility, if the net.interface.<interface>.config.gpsMode
property is not set, the GPS mode will be automatically set to the kuraModemGpsModeUnmanaged
equivalent.
net.interface.<interface>.config.vlan.parent
String Physical interface Vlan is bound to net.interface.<interface>.config.vlan.id
Integer Vlan tag identifier, between 0 and 4094 net.interface.<interface>.config.vlan.ingress
String Incoming traffic priorities in the format from:to, as comma separated pairs of unsigned integers (Optional) net.interface.<interface>.config.vlan.egress
String Outgoing traffic priorities in the format from:to, as comma separated pairs of unsigned integer (Optional) net.interface.<interface>.config.vlan.flags
String Configuration flags, between 0 and 15 (Optional) 1"},{"location":"gateway-configuration/network-configuration/#8021x-properties","title":"802.1x properties","text":"Name Type Description net.interface.<interface>.config.802-1x.eap
String The EAP method to be used when authenticating to the network with 802.1x. Supported methods: \"Kura8021xEapTls\", \"Kura8021xEapPeap\", \"Kura8021xEapTtls\". net.interface.<interface>.config.802-1x.innerAuth
String Specifies the \"phase 2\" inner authentication method when an EAP method that uses an inner TLS tunnel is specified in the \"eap\" property. Supported methods: \"Kura8021xInnerAuthNone\", \"Kura8021xInnerAuthMschapv2\". net.interface.<interface>.config.802-1x.identity
String Identity string for EAP authentication methods. Typically the user's user or login name. net.interface.<interface>.config.802-1x.password
String Password used for EAP authentication methods. net.interface.<interface>.config.802-1x.client-cert-name
String Name referring to the corresponding Kura keystore entry containing the client certificate if used by the EAP method specified in the \"eap\" property. Typically is set to the same name as the net.interface.<interface>.config.802-1x.private-key-name
when using EAP-TLS. net.interface.<interface>.config.802-1x.private-key-name
String Name referring to the corresponding Kura keystore entry containing the private key when the \"eap\" property is set to \"Kura8021xEapTls\". Typically is set to the same name as the net.interface.<interface>.config.802-1x.client-cert-name
. net.interface.<interface>.config.802-1x.ca-cert-name
String Name referring to the corresponding Kura keystore entry containing the CA certificate if used by the EAP method specified in the \"eap\" property. This parameter is optional but this allows man-in-the-middle attacks and is NOT recommended. net.interface.<interface>.config.802-1x.anonymous-identity
String Anonymous identity string for EAP authentication methods. Used as the unencrypted identity with EAP types that support different tunneled identity like EAP-TTLS (Optional)"},{"location":"gateway-configuration/network-configuration/#network-configuration-recipes","title":"Network Configuration recipes","text":"This section presents some snapshot examples to perform basic operations on networking. The snippets can be modified adapting them to the required configuration (i.e. changing the interface name in the property to be applied).
Warning
Be aware that an inconsitent or wrong configuration can compromise the network functionality of the gateway. Try the new configuration on a test device before appling it in a production environment!
Moreover, if a property is not present in the new snapshot, the old value is used for the configuration. So, the best practice is to set all the needed properties in the snapshot.
"},{"location":"gateway-configuration/network-configuration/#disable-a-network-interface","title":"Disable a network interface","text":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n <esf:configuration pid=\"org.eclipse.kura.net.admin.NetworkConfigurationService\">\n <esf:properties>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.type\" type=\"String\">\n <esf:value>ETHERNET</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.ip4.status\" type=\"String\">\n <esf:value>netIPv4StatusDisabled</esf:value>\n </esf:property>\n </esf:properties>\n </esf:configuration>\n</esf:configurations>\n
"},{"location":"gateway-configuration/network-configuration/#configure-an-ethernet-interface-for-wan-with-dhcp-client-enabled-and-custom-dns-server","title":"Configure an ethernet interface for WAN with DHCP client enabled and custom DNS server","text":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n <esf:configuration pid=\"org.eclipse.kura.net.admin.NetworkConfigurationService\">\n <esf:properties>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.type\" type=\"String\">\n <esf:value>ETHERNET</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.ip4.dnsServers\" type=\"String\">\n <esf:value>1.2.3.4</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.dhcpClient4.enabled\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.dhcpServer4.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.ip4.status\" type=\"String\">\n <esf:value>netIPv4StatusEnabledWAN</esf:value>\n </esf:property>\n </esf:properties>\n </esf:configuration>\n</esf:configurations>\n
"},{"location":"gateway-configuration/network-configuration/#configure-an-ethernet-interface-for-lan-with-dhcp-server-enabled-and-nat-disabled","title":"Configure an ethernet interface for LAN with DHCP server enabled and NAT disabled","text":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n <esf:configuration pid=\"org.eclipse.kura.net.admin.NetworkConfigurationService\">\n <esf:properties>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.type\" type=\"String\">\n <esf:value>ETHERNET</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.ip4.dnsServers\" type=\"String\">\n <esf:value/>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.dhcpClient4.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.ip4.status\" type=\"String\">\n <esf:value>netIPv4StatusEnabledLAN</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.dhcpServer4.rangeEnd\" type=\"String\">\n <esf:value>192.168.4.110</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.dhcpServer4.enabled\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.dhcpServer4.defaultLeaseTime\" type=\"Integer\">\n <esf:value>900</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.dhcpServer4.prefix\" type=\"Short\">\n <esf:value>24</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.dhcpServer4.passDns\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.dhcpServer4.rangeStart\" type=\"String\">\n <esf:value>192.168.4.100</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.dhcpServer4.maxLeaseTime\" type=\"Integer\">\n <esf:value>900</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.ip4.address\" type=\"String\">\n <esf:value>192.168.4.1</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.ip4.prefix\" type=\"Short\">\n <esf:value>24</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.ip4.gateway\" type=\"String\">\n <esf:value/>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.enp5s0.config.nat.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n </esf:properties>\n </esf:configuration>\n</esf:configurations>\n
"},{"location":"gateway-configuration/network-configuration/#configure-a-wireless-interface-as-access-point-with-dhcp-server-and-nat-enabled","title":"Configure a wireless interface as access point with DHCP server and NAT enabled","text":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n <esf:configuration pid=\"org.eclipse.kura.net.admin.NetworkConfigurationService\">\n <esf:properties>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.type\" type=\"String\">\n <esf:value>WIFI</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.ip4.status\" type=\"String\">\n <esf:value>netIPv4StatusEnabledLAN</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.ip4.gateway\" type=\"String\">\n <esf:value/>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.ip4.dnsServers\" type=\"String\">\n <esf:value/>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.ip4.prefix\" type=\"Short\">\n <esf:value>24</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.ip4.address\" type=\"String\">\n <esf:value>172.16.1.1</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.dhcpClient4.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.dhcpServer4.rangeStart\" type=\"String\">\n <esf:value>172.16.1.100</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.dhcpServer4.maxLeaseTime\" type=\"Integer\">\n <esf:value>900</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.dhcpServer4.defaultLeaseTime\" type=\"Integer\">\n <esf:value>900</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.dhcpServer4.rangeEnd\" type=\"String\">\n <esf:value>172.16.1.110</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.dhcpServer4.prefix\" type=\"Short\">\n <esf:value>24</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.dhcpServer4.enabled\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.dhcpServer4.passDns\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.nat.enabled\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.mode\" type=\"String\">\n <esf:value>MASTER</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.master.driver\" type=\"String\">\n <esf:value>nl80211</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"true\" name=\"net.interface.wlp1s0.config.wifi.master.passphrase\" type=\"Password\">\n <esf:value>ZW5hYmxlbWVwbGVhc2U=</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.master.ssid\" type=\"String\">\n <esf:value>kura_gateway_19</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.master.securityType\" type=\"String\">\n <esf:value>SECURITY_WPA2</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.master.mode\" type=\"String\">\n <esf:value>MASTER</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.master.channel\" type=\"String\">\n <esf:value>11</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.master.radioMode\" type=\"String\">\n <esf:value>RADIO_MODE_80211g</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.master.ignoreSSID\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.master.pairwiseCiphers\" type=\"String\">\n <esf:value>CCMP</esf:value>\n </esf:property>\n </esf:properties>\n </esf:configuration>\n</esf:configurations>\n
"},{"location":"gateway-configuration/network-configuration/#configure-a-wireless-interface-as-station-mode-with-dhcp-client-enabled","title":"Configure a wireless interface as station mode with DHCP client enabled","text":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n <esf:configuration pid=\"org.eclipse.kura.net.admin.NetworkConfigurationService\">\n <esf:properties>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.type\" type=\"String\">\n <esf:value>WIFI</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.ip4.status\" type=\"String\">\n <esf:value>netIPv4StatusEnabledLAN</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.ip4.dnsServers\" type=\"String\">\n <esf:value/>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.dhcpClient4.enabled\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.dhcpServer4.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.mode\" type=\"String\">\n <esf:value>INFRA</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.infra.ssid\" type=\"String\">\n <esf:value>MyWirelessNetwork</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.infra.bgscan\" type=\"String\">\n <esf:value/>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"true\" name=\"net.interface.wlp1s0.config.wifi.infra.passphrase\" type=\"Password\">\n <esf:value>MyPasswordBase64</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.infra.ignoreSSID\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.infra.mode\" type=\"String\">\n <esf:value>INFRA</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.infra.pingAccessPoint\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.infra.driver\" type=\"String\">\n <esf:value>nl80211</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.wlp1s0.config.wifi.infra.securityType\" type=\"String\">\n <esf:value>SECURITY_WPA2</esf:value>\n </esf:property>\n </esf:properties>\n </esf:configuration>\n</esf:configurations>\n
"},{"location":"gateway-configuration/network-configuration/#enable-a-cellular-interface","title":"Enable a cellular interface","text":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n <esf:configuration pid=\"org.eclipse.kura.net.admin.NetworkConfigurationService\">\n <esf:properties> \n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.type\" type=\"String\">\n <esf:value>MODEM</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.ip4.status\" type=\"String\">\n <esf:value>netIPv4StatusEnabledWAN</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.ip4.dnsServers\" type=\"String\">\n <esf:value/>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.dhcpClient4.enabled\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.dhcpServer4.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.idle\" type=\"Integer\">\n <esf:value>95</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"true\" name=\"net.interface.1-1.config.password\" type=\"Password\">\n <esf:value/>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.pdpType\" type=\"String\">\n <esf:value>IP</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.ipAddress\" type=\"String\">\n <esf:value/>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.maxFail\" type=\"Integer\">\n <esf:value>5</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.authType\" type=\"String\">\n <esf:value>NONE</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.lcpEchoInterval\" type=\"Integer\">\n <esf:value>0</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.enabled\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.activeFilter\" type=\"String\">\n <esf:value>inbound</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.lcpEchoFailure\" type=\"Integer\">\n <esf:value>0</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.diversityEnabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.resetTimeout\" type=\"Integer\">\n <esf:value>5</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.gpsEnabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.persist\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.dialString\" type=\"String\">\n <esf:value>atd*99***2#</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.1-1.config.apn\" type=\"String\">\n <esf:value>web.omnitel.it</esf:value>\n </esf:property>\n </esf:properties>\n </esf:configuration>\n</esf:configurations>\n
"},{"location":"gateway-configuration/network-configuration/#create-a-vlan","title":"Create a VLAN","text":"<?xml version=\"1.0\" encoding=\"UTF-8\"?><esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n <esf:configuration pid=\"org.eclipse.kura.net.admin.NetworkConfigurationService\">\n <esf:properties>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interfaces\" type=\"String\">\n <esf:value>wlan0,lo,ens33,vlanFull,ens34</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.dhcpServer4.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.nat.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.dhcpClient4.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.type\" type=\"String\">\n <esf:value>VLAN</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.ip4.status\" type=\"String\">\n <esf:value>netIPv4StatusEnabledLAN</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.vlan.parent\" type=\"String\">\n <esf:value>ens33</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.vlan.id\" type=\"Integer\">\n <esf:value>41</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.vlan.flags\" type=\"Integer\">\n <esf:value>1</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.vlan.ingress\" type=\"String\">\n <esf:value>1:2,3:4</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.vlan.egress\" type=\"String\">\n <esf:value>5:6</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.ip4.address\" type=\"String\">\n <esf:value>192.168.41.100</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.ip4.prefix\" type=\"Short\">\n <esf:value>24</esf:value>\n </esf:property>\n </esf:properties>\n </esf:configuration>\n</esf:configurations>\n
"},{"location":"gateway-configuration/network-failover/","title":"Network Failover","text":"For devices configured to use NetworkManager, it is possible to configure multiple WAN interfaces and a basic network failover functionality.
As in the picture below, the Kura UI allows for multiple WAN interfaces to be defined. Each WAN interface can be configured with a WAN Priority. WAN Priority is used to determine which interface will be selected for primary WAN. In the case where the primary WAN interface loses connection, then the next highest priority interface is assigned.
Kura uses NetworkManager's implementation to achieve network failover (see NetworkManager). Lower values correspond to higher priority. Allowed values range from -1 to 2147483647. Value -1 means that the metric is chosen automatically based on the device type (see NetworkManager DBUS properties).
To observe changes to the applied configuration, use the following command on your device's shell:
route -n\n\nKernel IP routing table\nDestination Gateway Genmask Flags Metric Ref Use Iface\n0.0.0.0 192.168.2.1 0.0.0.0 UG 100 0 0 eth0\n172.16.1.0 0.0.0.0 255.255.255.0 U 600 0 0 wlan0\n172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0\n192.168.2.0 0.0.0.0 255.255.255.0 U 100 0 0 eth0\n
The metric
flag will correspond to the set WAN Priority. NetworkManager will always prioritize lower metric routes.
The NetworkManager failover mechanism can work at two different levels:
NetworkManager brings a network interface down when it detects the loss of its physical link. In such case, the next highest priority interface is selected as the main one.
When the connectivity check fails, NetworkManager penalizes the metric of that interface in the routing table. NetworkManager continues to perform connectivity checks over all the other interfaces. As soon as the connectivity is restored over a previously failing interface, the metric is also restored to the original value and the routing table goes back to the original state.
"},{"location":"gateway-configuration/network-failover/#configuring-the-connectivity-check","title":"Configuring the connectivity check","text":"The connectivity check is enabled by default in Kura and is configured to probe the connection to http://network-test.debian.org/nm
every 60 seconds. To set a specific URI and a different interval edit /etc/NetworkManager/conf.d/99kura-nm.conf
(reference NetworkManager):
[connectivity]\nuri=http://network-test.debian.org/nm\ninterval=60\nresponse=\"NetworkManager is online\"\n
The minimun interval is 60 seconds, if no interval is specified it defaults to 300 seconds.
The response should match what the URI is returning when probed. Some examples of web pages with NetworkManager responses:
URI Responsehttp://network-test.debian.org/nm
NetworkManager is online
https://fedoraproject.org/static/hotspot.txt
OK
http://nmcheck.gnome.org/check_network_status.txt
NetworkManager is online
https://www.pkgbuild.com/check_network_status.txt
NetworkManager is online
To disable the connectivity check feature:
[connectivity]
section from the configuration file; orinterval=0
; oruri
; oruri=
Each interface in the Network page contains inside its specific box the tab Hardware
: this collects the most significant information about the current state of the interface.
In this way the user can have a quick and complete view of what are the settings and physical specifications of a network interface.
These information are respectively:
UNMANAGED
, ACTIVATED
, FAILED
, UNKNOWN
.WIFI
or ETHERNET
These entries are filled only if the associated data is available. This means, for example, that no information will be shown under Current WLAN Channel
if the interface is of Ethernet type. Conversely, if the interface is Wifi type and no information is shown, it is possible that there has been some problem with the configuration or connection of the interface.
So this tab, could be also an intuitive way to check if the interface is working properly or not.
"},{"location":"gateway-configuration/network-threat-manager/","title":"Network Threat Manager","text":"Eclipse Kura provides a set of features to detect and prevent network attacks. The Security section in the Gateway Administration Console shows the Network Threat Manager tab where is it possible to activate these functions.
Warning
The Network Threat Manager tab is not available for the No Network version of Eclipse Kura.
"},{"location":"gateway-configuration/network-threat-manager/#flooding-protection","title":"Flooding protection","text":"The flooding protection function is used to prevent DDos (Distributed Denial-of-Service) attacks using the firewall. When enabled, the feature adds a set of firewall rules to the mangle table.
"},{"location":"gateway-configuration/network-threat-manager/#flooding-protection-for-ipv4","title":"Flooding protection for IPv4","text":"The following rules are added to the mangle table and they are implemented to block invalid or malicious network packets:
iptables -A prerouting-kura -m conntrack --ctstate INVALID -j DROP\niptables -A prerouting-kura -p tcp ! --syn -m conntrack --ctstate NEW -j DROP\niptables -A prerouting-kura -p tcp -m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags FIN,SYN FIN,SYN -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags SYN,RST SYN,RST -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags FIN,RST FIN,RST -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags FIN,ACK FIN -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags ACK,URG URG -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags ACK,FIN FIN -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags ACK,PSH PSH -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags ALL ALL -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags ALL NONE -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags ALL SYN,FIN,PSH,URG -j DROP\niptables -A prerouting-kura -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP\niptables -A prerouting-kura -p icmp -j DROP\niptables -A prerouting-kura -f -j DROP\n
To further filter the incoming TCP fragmented packets, specific system configuration files are configured. The flooding.protection.enabled property is used to enable the feature.
"},{"location":"gateway-configuration/network-threat-manager/#flooding-protection-for-ipv6","title":"Flooding protection for IPv6","text":"The same rules applied to the IPv4 are used for preventing attack on IPv6. In addition, some rules are implemented to drop specific IPv6 headers and limit the incoming ICMPv6 packets. Moreover, the incoming TCP fragmented packets are dropped configuring specific system files.
The following rules are applied to the mangle table:
ip6tables -A prerouting-kura -m conntrack --ctstate INVALID -j DROP\nip6tables -A prerouting-kura -p tcp ! --syn -m conntrack --ctstate NEW -j DROP\nip6tables -A prerouting-kura -p tcp -m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags FIN,SYN FIN,SYN -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags SYN,RST SYN,RST -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags FIN,RST FIN,RST -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags FIN,ACK FIN -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags ACK,URG URG -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags ACK,FIN FIN -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags ACK,PSH PSH -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags ALL ALL -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags ALL NONE -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags ALL SYN,FIN,PSH,URG -j DROP\nip6tables -A prerouting-kura -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP\nip6tables -A prerouting-kura -p ipv6-icmp -m ipv6-icmp --icmpv6-type 128 -j DROP\nip6tables -A prerouting-kura -p ipv6-icmp -m ipv6-icmp --icmpv6-type 129 -j DROP\nip6tables -A prerouting-kura -m ipv6header --header dst --soft -j DROP\nip6tables -A prerouting-kura -m ipv6header --header hop --soft -j DROP\nip6tables -A prerouting-kura -m ipv6header --header route --soft -j DROP\nip6tables -A prerouting-kura -m ipv6header --header frag --soft -j DROP\nip6tables -A prerouting-kura -m ipv6header --header auth --soft -j DROP\nip6tables -A prerouting-kura -m ipv6header --header esp --soft -j DROP\nip6tables -A prerouting-kura -m ipv6header --header none --soft -j DROP\nip6tables -A prerouting-kura -m rt --rt-type 0 -j DROP\nip6tables -A output-kura -m rt --rt-type 0 -j DROP\n
Also in this case, to enable the feature and add the rules to the firewall, the flooding.protection.enabled.ipv6 property has to be set to true. If the device doesn't support IPv6, this property is ignored.
Warning
To recover the device state when the IPv6 flooding protection feature is disabled, a reboot is required. So, to disable the feature, set the flooding.protection.enabled.ipv6 property to false tha reboot the device.
"},{"location":"gateway-configuration/ssl-configuration/","title":"SSL Configuration","text":"A SSL Service instance manages the configuration of the SSL connections. It uses the associated KeystoreService to access the trust certificates, private keys pairs needed to setup a SSL connection. It also enforces best practices that are not enabled by default in the Java VM, such as, enabling hostname verification, disabling the legacy SSL-2.0-compatible Client Hello, and disabling the Nagle algorithm.
The list of all available SSL Service instances is available in the SSL Configuration tab of the Security section, accessible only by the users with the corresponding permission.
By default, the framework creates a SSLManagerService instance with the org.eclipse.kura.ssl.SslManagerService
PID. This instance is generally used by all the core services of the framework.
A new SSL Service instance can be created using the New Button, by specifying the desired factory and the Service PID that will be associated with this new instance.
An instance of the default org.eclipse.kura.ssl.SslManagerService
factory has the following configuration parameters:
KeystoreService Target Filter - specifies, as an OSGi target filter, the pid of the KeystoreService used to manage the SSL key store (Required field).
Truststore Target Filter - specifies, as an OSGi target filter, the pid of the KeystoreService used to manage the SSL trust store. If the target service cannot be found, the service configured with the Keystore Target Filter parameter will be used as truststore.
ssl.default.protocol - defines the allowed SSL protocol.
ssl.hostname.verification - indicates whether hostname verification is enabled or disabled.
ssl.default.cipherSuites - defines the allowed cipher suites.
By selecting the Select available targets button, the user can associate the SSLManagerService instance with the corresponding KeystoreService instances available in the framework runtime.
"},{"location":"gateway-configuration/ssl-configuration/#server-ssl-certificate","title":"Server SSL Certificate","text":"The device requires a public key in its trust store in order to authenticate the broker and be able to setup an SSL connection. Kura is distributed with a pre-initialized SSL keystore that contains only some of the major Certification Authorities (CA) public keys.
If the broker uses a certificate signed by a different CA, or uses an auto-signed certificate, the system administrator must setup Kura with the correct certificates used to trust the remote cloud broker.
The inclusion of public certificates is accomplished with the Server SSL Certificate feature. To do so, the SSL Certificates form must be completed by providing a certificate or a certificates chain to be trusted and defining the alias used to register this new data in the device's trust store.
With this feature, when the device tries to instantiate an SSL connection with the broker, it receives the broker's public key chain. The SSL connection is secured only if the received chain is trusted. This connection can only happen if one of the certificates that compose the broker chain are available in the device's trust store.
When instantiating the device's trust store, the user decides whether to add a single certificate (leaf or CA certificate) or the full chain.
In the latter case, the chain should be provided by specifying the leaf certificate, followed by the CA certificate that is signing it, and so on, until the root CA is reached. An example of this scenario is depicted in the following image:
"},{"location":"gateway-configuration/ssl-configuration/#device-ssl-certificate-mutual-authentication","title":"Device SSL Certificate & Mutual Authentication","text":"Mutual authentication is a technique that allows authentication of the device that is connecting to the broker. The form available in Certificates List may be used to specify the keys needed to enable mutual authentication.
This authentication may be accomplished by specifying a couple of certificates (private and public keys) to be used by the client device to authenticate itself to the broker. This authentication is possible because the broker has the root CA certificate that has been used to sign the couple held by the device. In this way, the authenticity of the couple of certificates held by the device may be verified, and therefore, enable the two communicating parts (the broker and the device) to trust each other.
To enable mutual authentication, the user must complete the form with a well-formed key pair (public and private), and with an alias value that corresponds with the account name used to connect to the broker.
"},{"location":"gateway-configuration/ssl-configuration/#key-pair-generation","title":"Key Pair Generation","text":"The keys may be generated using specific software, such as OpenSSL or Keytool. This section describes how to use OpenSSL to generate a couple of private and public keys.
The private key may be created using the following command:
openssl genrsa -out certsDirectory/certs/certificate.key 1024\n
This command creates a new, 1024-bit private key in the specified path. This key is used to generate a Certificate Signing Request (CSR) file, which is used by a CA to authenticate the certificate's creator. A CSR file is created with OpenSSL using the following command:
openssl req -new -key certsDirectory/certs/certificate.key -out certsDirectory/crl/certificate.csr\n
If the user is creating their own certificate chain, the CSR file may be signed using a personal CA. This process may be accomplished using OpenSSL with the following command:
openssl ca -config certsDirectory/openssl.cnf -days 3650 -keyfile certsDirectory/ca/ca.key -cert certsDirectory/ca/ca.pem -out certsDirectory/certs/certificate.pem -infiles certsDirectory/crl/certificate.csr\n
The parameters are defined as follows:
-config: specifies the OpenSSL configuration file that must be used to sign the certificate.
-days: specifies how long the certificate is valid.
-keyfile and -cert: allow the specification of the CA that will sign the CSR file.
-out: identifies the location and the name of the signed certificate that will be created.
-infiles: identifies the location of the CSR file that has to be signed.
Tip
The private key may not be placed into the Kura Gateway Administration Console without a format conversion.
OpenSSL offers the following command to convert the input private key to a non-encrypted PKCS#8 format that may be processed by the Kura code:
openssl pkcs8 -topk8 -inform PEM -outform PEM -in inPrivateKey.key -out outKey.pem -nocrypt\n
"},{"location":"gateway-configuration/vlan-configuration/","title":"VLAN Configuration","text":"For devices running Kura installed using a Generic Profile, it is possible to configure multiple VLAN interfaces. Take a look at our installer profiles to know which are supported.
A VLAN, or Virtual Local Area Network, is a network segmentation technology that allows a single physical network to be logically divided into multiple isolated networks. These virtual networks operate as if they are independent, even though they share the same physical infrastructure. This is achieved via a VLAN ID, or VLAN tag, a numerical label added to network frames to identify the specific Virtual Local Area Network (VLAN) to which they belong. It's a critical component in VLAN technology, allowing network switches and routers to differentiate and route traffic within a VLAN. VLAN tags are added to the Ethernet frame's header, indicating which virtual network a data packet should be directed to when it traverses the physical network infrastructure. Therefore, VLANs must also be supported and configured on the network equipment a device is connected to.
A VLAN can be named freely, as long as it's 15 or less characters. A typical VLAN naming format is physicalInterfaceName
.vlanId
(eg. a vlan with id 100 on the interface eth0 would be named eth0.100).
This is achieved by NetworkManager by creating a virtual device bound to the underlying physical interface when Kura sets up a new VLAN connection.
"},{"location":"gateway-configuration/vlan-configuration/#vlan-configuration-via-kura-snapshot-upload","title":"VLAN Configuration via Kura Snapshot upload","text":"Currently, VLAN configuration is supported via uploading snapshot.xml fragments.
Warning
When creating a new VLAN be sure to include the net.interfaces
parameter, containing both the previously existing network interfaces, either virtual or physical, and the name of the new VLAN to be created.
The following example creates a VLAN with ID 40 over the ethernet interface ens33, naming it ens33.40
, using a predefined IP address, enabled for LAN.
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n <esf:configuration pid=\"org.eclipse.kura.net.admin.NetworkConfigurationService\">\n <esf:properties>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interfaces\" type=\"String\">\n <esf:value>lo,ens33,ens34,ens33.40</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.40.config.dhcpServer4.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.40.config.nat.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.40.config.dhcpClient4.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.40.type\" type=\"String\">\n <esf:value>VLAN</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.40.config.ip4.status\" type=\"String\">\n <esf:value>netIPv4StatusEnabledLAN</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.40.config.vlan.parent\" type=\"String\">\n <esf:value>ens33</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.40.config.vlan.id\" type=\"Integer\">\n <esf:value>40</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.40.config.ip4.address\" type=\"String\">\n <esf:value>10.0.55.37</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.40.config.ip4.prefix\" type=\"Short\">\n <esf:value>24</esf:value>\n </esf:property>\n </esf:properties>\n </esf:configuration>\n</esf:configurations>\n
"},{"location":"gateway-configuration/vlan-configuration/#complete-vlan-configuration-example","title":"Complete VLAN configuration example","text":"The following example creates a VLAN with ID 41 over the ethernet interface ens33, naming it ens33.41
, using a predefined IP address, enabled for WAN. This example also sets the 'flags' and 'traffic priority' optional parameters as described in Network Manager API documentation.
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n <esf:configuration pid=\"org.eclipse.kura.net.admin.NetworkConfigurationService\">\n <esf:properties>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interfaces\" type=\"String\">\n <esf:value>lo,ens33,ens34,ens33.41</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.dhcpServer4.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.nat.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.dhcpClient4.enabled\" type=\"Boolean\">\n <esf:value>false</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.type\" type=\"String\">\n <esf:value>VLAN</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.ip4.gateway\" type=\"String\">\n <esf:value>192.168.41.254</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.ip4.status\" type=\"String\">\n <esf:value>netIPv4StatusEnabledWAN</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.vlanFull.config.ip4.dnsServers\" type=\"String\">\n <esf:value>8.8.8.8</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.vlan.parent\" type=\"String\">\n <esf:value>ens33</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.vlan.id\" type=\"Integer\">\n <esf:value>41</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.ip4.address\" type=\"String\">\n <esf:value>192.168.41.1</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.ip4.prefix\" type=\"Short\">\n <esf:value>24</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.vlan.flags\" type=\"Integer\">\n <esf:value>1</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.vlan.ingress\" type=\"String\">\n <esf:value>1:2,3:4</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.41.config.vlan.egress\" type=\"String\">\n <esf:value>5:6</esf:value>\n </esf:property>\n </esf:properties>\n </esf:configuration>\n</esf:configurations>\n
"},{"location":"gateway-configuration/vlan-configuration/#vlan-management","title":"VLAN Management","text":"Once a VLAN is created it can be managed via the Kura UI just like any other Ethernet interface.
Warning
Setting a VLAN status to \"Disabled\" deletes its configuration in NetworkManager and the related virtual interface from the system. Although it will is no longer be visible on the UI, all the configurations are left in Kura. Therefore the VLAN can be restored by setting the net.interface.<interface>.config.ip4.status
to netIPv4StatusEnabledLAN
or netIPv4StatusEnabledWAN
via snapshot upload, then resume configuration via UI.
As an example, the configuration to reactivate a disabled VLAN named ens33.40 would be as follows:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n <esf:configuration pid=\"org.eclipse.kura.net.admin.NetworkConfigurationService\">\n <esf:properties>\n <esf:property array=\"false\" encrypted=\"false\" name=\"net.interface.ens33.40.config.ip4.status\" type=\"String\">\n <esf:value>netIPv4StatusEnabledLAN</esf:value>\n </esf:property>\n </esf:properties>\n </esf:configuration>\n</esf:configurations>\n
"},{"location":"gateway-configuration/web-console-configuration/","title":"Web Console Configuration","text":"The Web Console exposes a set of configuration parameters that can be used to increase the overall UI security. The Web Console configuration can be accessed in the Security section.
"},{"location":"gateway-configuration/web-console-configuration/#web-server-entry-point","title":"Web Server Entry Point","text":"This parameter allows to configure the relative path that the user will be redirected to when accessing http(s)://gateway-ip/. Note: this parameter does not change the Kura Web UI relative path, that is always /admin/console. The default value set is /admin/console
"},{"location":"gateway-configuration/web-console-configuration/#session-max-inactivity-interval","title":"Session max inactivity interval","text":"The session max inactivity interval in minutes. If no interaction with the Web UI is performed for the value of this parameter in minutes, a new login will be requested. The default value set is 15 minutes
"},{"location":"gateway-configuration/web-console-configuration/#access-banner-enabled","title":"Access Banner Enabled","text":"For security reasons, it may be needed to display to the user a banner that describes the intended system use before authenticating.
Once enabled and configured, the Kura Web UI will display a banner before every access attempt, as depicted in the image below.
"},{"location":"gateway-configuration/web-console-configuration/#password-management","title":"Password Management","text":"This section is related to the definition of required parameters that must be respected when defining a new password, for example when a user changes its password at first access.
"},{"location":"gateway-configuration/web-console-configuration/#minimum-password-length","title":"Minimum password length","text":"The minimum length to be enforced for new passwords. Set to 0 to disable. The default value set is 8 characters
"},{"location":"gateway-configuration/web-console-configuration/#require-digits-in-new-password","title":"Require digits in new password","text":"If set to true, new passwords will be accepted only if containing at least one digit. The default value is false
"},{"location":"gateway-configuration/web-console-configuration/#require-special-characters-in-new-password","title":"Require special characters in new password","text":"If set to true, new passwords will be accepted only if containing at least one non alphanumeric character The default value is false
"},{"location":"gateway-configuration/web-console-configuration/#require-uppercase-and-lowercase-characters-in-new-passwords","title":"Require uppercase and lowercase characters in new passwords","text":"If set to true, new passwords will be accepted only if containing both uppercase and lowercase alphanumeric characters. The default value is false
"},{"location":"gateway-configuration/web-console-configuration/#allowed-ports","title":"Allowed ports","text":"If set to a non empty list, Web Console access will be allowed only on the specified ports. If set to an empty list, access will be allowed on all ports. It is needed for the end user to make sure that the allowed ports are open in HttpService and Firewall configuration.
"},{"location":"gateway-configuration/web-console-configuration/#authentication-method-password-enabled","title":"Authentication Method \"Password\" Enabled","text":"Defines whether the \"Password\" authentication method is enabled or not. The default value is true
"},{"location":"gateway-configuration/web-console-configuration/#authentication-method-certificate-enabled","title":"Authentication Method \"Certificate\" Enabled","text":"Defines whether the \"Certificate\" authentication method is enabled or not The default value is true
"},{"location":"gateway-configuration/web-console-configuration/#sslmanagerservice-target-filter","title":"SslManagerService Target Filter","text":"It is possible to specify the SslManagerService containing the certificates truststore required to establish a new https connection, this is needed, for example, for fetching package descriptions from Eclipse Marketplace. The default target is the org.eclipse.kura.ssl.SslManagerService
"},{"location":"gateway-configuration/wifi-configuration-8021x/","title":"Wi-Fi 802.1x Configuration","text":"Enterprise Wi-Fi is currently only supported on gateways running our generic profiles. The following is a list of currently supported 802.1x authentication methods.
WPA2/WPA3-Enterprise
TTLS
MSCHAPV2
Identity (Username)
Password
The configuration should look like the following:
"},{"location":"gateway-configuration/wifi-configuration-8021x/#peap-mschapv2","title":"PEAP-MSCHAPv2","text":"WPA2/WPA3-Enterprise
PEAP
MSCHAPV2
Identity (Username)
Password
The configuration should look like the following:
"},{"location":"gateway-configuration/wifi-configuration-8021x/#eap-tls","title":"EAP-TLS","text":"To connect via EAP-TLS you will need the following items in unencrypted PEM format:
Security
under the System
tab.Keystore Configuration
add a new keystore, and keep note of the name. Certificate List
and create a new Certificate. Insert the PEM and Apply, keep note of the name. add
and create a new Private Key. Insert both the certificates in the PEM in the dialogue and press apply. keep note of the name. WPA2/WPA3-Enterprise
. TLS
.Identity (Username)
.Keystore Pid
to the name of the keystore created above.Certificate Authority Certificate (CA-Cert)
to the name of the certificate created above.Client Private Key
to the name of the Private Key created above.When completed the Wi-Fi configuration should look like the following:
"},{"location":"gateway-configuration/wifi-configuration/","title":"Wi-Fi Configuration","text":"From a configuration standpoint, the Wi-Fi interface (e.g., wlan0) may be viewed as an extension of Ethernet. In addition to the TCP/IP and DHCP & NAT configuration tabs, it has the Wireless tab that allows for the configuration of wireless settings. These configuration options are described below.
Warning
Before using wifi make sure that you have correctly set the Regulatory Domain on the gateway. You can check the current configuration using the iw reg get
command. To set the Regulatory Domain please refer to the specific section in the Gateway Configurations.
The Wireless tab contains the following configuration parameters:
Wireless Mode: defines the mode of operation.
Network Name: specifies the Service Set Identifier (SSID).
Radio Mode: defines 802.11 mode.
Wireless Security: sets the security protocol for the wireless network.
Wireless Password: sets the password for the wireless network.
Verify Password: sets the password verification field.
Pairwise Ciphers: lists accepted pairwise (unicast) ciphers for WPA/WPA2.
Group Ciphers: lists accepted group (broadcast/multicast) ciphers for WPA/WPA2.
Bgscan Module: requests background scans for the purpose of roaming within an ESS (i.e., within a single network block with all the APs using the same SSID).
Bgscan Signal Strength Threshold: defines a threshold (in dBm) that determines which one of the following two parameters (i.e., Short Interval or Long Interval) will be effective.
Bgscan Short Interval: defines the interval between background scans (in seconds) if the actual signal level of the currently connected access point is worse than signal_strength.
Bgscan Long Interval: defines the interval between background scans (in seconds) if the actual signal level of the currently connected access point is better than signal_strength.
Ping Access Point & renew DHCP lease if not reachable: enables pinging the access point after connection is established.
Ignore Broadcast SSID: operates as follows if set to true:
Channels table: allows the selection of desired channel frequencies. The availability of the desired frequency is subject to the Regdom set on the device. For a list of limitations in different countries you can consult the following page: List of WLAN channels. Channels marked as No Irradiation and Radar Detection can be used only if DFS (Dynamic Frequency Selection) is supported by the Wi-Fi chip.
In addition to the options described above, the Wireless configuration display provides two buttons that help to configure Wi-Fi in the Station mode. These buttons are described below.
Access Point Scan: clicking this button triggers access point scan operations. Upon a successful scan, a table containing access points within range is presented. This table contains the following information:
If you select one of these access points, respective wireless controls (i.e., Network Name, Wireless Security, and Channel) are filled with information obtained during the scan operation.
Password Verification: clicking this button triggers password verification before a full connection is established.
Generic Profiles Access Point Scan Issue
Due to a limitation in our current implementation of Access Point scanning in the generic profiles, a scan triggered while the device Wireless Mode is set as Access Point will result in it reporting itself as the only reachable Access Point.
To retrieve the actual list of nearby Access Points, set your device in Station Mode with a temporary configuration and trigger the scan again.
"},{"location":"gateway-configuration/wifi-configuration/#wi-fi-linux-configuration","title":"Wi-Fi Linux Configuration","text":"This section describes the changes applied by Kura at the Linux networking configuration. Please read the following note before proceeding with manual changes of the Linux networking configuration.
Warning
It is NOT recommended performing manual editing of the Linux networking configuration files when the gateway configuration is being managed through Kura. While Linux may correctly accept manual changes, Kura may not be able to interpret the new configuration resulting in an inconsistent state.
When the Wi-Fi configuration for the Access Point mode is submitted, Kura generates the /etc/hostapd.conf
file and launches the hostapd program as shown below.
hostapd:B /etc/hostapd.conf\n
# /etc/hostapd/hostapd.conf\n\ninterface=wlan0\n\ndriver=nl80211\n\n# SSID to use. This will be the \"name\" of the accesspoint\nssid=kura_gateway_00:E0:C7:09:35:D8\n\n# basic operational settings\nhw_mode=g\n\nwme_enabled=0\nieee80211n=0\n\nchannel=1\n\n# Logging and debugging settings: more of this in original config file\nlogger_syslog=-1\nlogger_syslog_level=2\nlogger_stdout=-1\nlogger_stdout_level=2\ndump_file=/tmp/hostapd.dump\n\n# WPA settings. We'll use stronger WPA2\n# bit0 = WPA\n# bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled)\nwpa=2\n\n# Preshared key of between 8-63 ASCII characters.\n# If you define the key in here, make sure that the file is not readable\n# by anyone but root. Alternatively you can use a separate file for the\n# key; see original hostapd.conf for more information.\nwpa_passphrase=testKEYS\n\n# Key management algorithm. In this case, a simple pre-shared key (PSK)\nwpa_key_mgmt=WPA-PSK\n\n# The cipher suite to use. We want to use stronger CCMP cipher.\nwpa_pairwise=CCMP\n\n# Change the broadcasted/multicasted keys after this many seconds.\nwpa_group_rekey=600\n\n# Change the master key after this many seconds. Master key is used as a basis\n# (source) for the encryption keys.\nwpa_gmk_rekey=86400\n\n# Send empty SSID in beacons and ignore probe request frames that do not\n# specify full SSID, i.e., require stations to know SSID.\n# default: disabled (0)\n# 1 = send empty (length=0) SSID in beacon and ignore probe request for\n# broadcast SSID\n# 2 = clear SSID (ASCII 0), but keep the original length (this may be required\n# with some clients that do not support empty SSID) and ignore probe\n# requests for broadcast SSID\nignore_broadcast_ssid=0\n
When the Wi-Fi configuration for the Station mode is submitted, Kura generates the /etc/wpa_supplicant.conf
file and launches the wpa_supplicant
program as shown below.
wpa_supplicant:B:D nl80211:i wlan0:c /etc/wpa_supplicant.conf\n
# /etc/wpa_supplicant.conf\n# allow frontend (e.g., wpa_cli) to be used by all users in 'wheel' group\nctrl_interface=/var/run/wpa_supplicant\nctrl_interface_group=wheel\n\n# home network; allow all valid ciphers\nnetwork={\n mode=0\n ssid=\"Eurotech-INC\"\n scan_ssid=1\n key_mgmt=WPA-PSK\n psk=\"WG4t3101\"\n proto=RSN\n pairwise=CCMP TKIP\n group=CCMP TKIP\n scan_freq=2412\n bgscan=\"\"\n}\n
"},{"location":"getting-started/docker-quick-start/","title":"Docker Quick Start","text":""},{"location":"getting-started/docker-quick-start/#installation","title":"Installation","text":"Eclipse Kura is also available as a Docker container available in Docker Hub.
To download and run, use the following command:
docker run -d -p 443:443 -t eclipse/kura\n
This command will start Kura in background and the Kura Web Ui will be available through port 443.
Once the image is started you can navigate your browser to https://localhost and log in using the credentials admin : admin
.
Following, a set of useful Docker command that can be used to list and manage Docker containers. For more details on Docker commands, please reference the official Docker documentation
"},{"location":"getting-started/docker-quick-start/#list-docker-images","title":"List Docker Images","text":"To list all the installed Docker images run:
docker images\n
"},{"location":"getting-started/docker-quick-start/#list-running-docker-containers","title":"List Running Docker Containers","text":"To list all the available instances (both running and powered off) run:
docker ps -a\n
"},{"location":"getting-started/docker-quick-start/#startstop-a-docker-container","title":"Start/Stop a Docker Container","text":"docker stop <container id>\ndocker start <container id>\n
where <container id>
is the instance identification number.
Kura is provided using a DEB Linux package. Visit the Kura download page to find the correct installation file for the target system.
"},{"location":"getting-started/install-kura/#installer-types","title":"Installer types","text":"Several installers can be found on such page, and they fall into one of the following categories:
kura-5.5.0_generic-arm32_installer.deb
; andkura_5.5.0_nvidia-jetson-nano-nn_installer.deb
Profiles of types (1) and (2) ship a Kura version with networking functionalities. In particular, the installers of kind (1) use Kura Networking for leveraging network interface configurations and are made for a specific device.
Installers of type (2) can be installed on targets with NetworkManager; a commonly available tool for managing Linux networking. Kura leverages this tool for networking functionalities. Refer to the Generic installers section for further information.
Installers of type (3) with the suffix nn
are No Networking profiles that do not bundle the Kura Network Manager: all the network configurations need to be done outside of Kura. Functionalities missing in NN profiles compared to the full Kura profiles:
Kura can be installed using the generic profiles:
kura-<kura-version>_generic-<arch>_installer.deb/rpm\n
where <arch>
is one of the supported architectures: x86_64, arm32, and arm64. A generic Kura profile can work on systems that have available the dependencies listed in the Kura dependencies section, and that have at least one physical ethernet interface.
Eclipse Kura's Generic profile incorporates an adaptive Heap Memory allocation system during installation. The allocation follows a formula based on your gateway's available memory. If your gateway has less than 1024MB of RAM, Kura will set -Xms and -Xmx to 256MB. For gateways with more than 1024MB, one quarter of the total RAM will be assigned to -Xms and -Xmx.
"},{"location":"getting-started/install-kura/#initial-network-configuration","title":"Initial network configuration","text":"During the installation of Eclipse Kura with network management support, the initial network configuration will be generated dynamically. The existing wired and wireless network interface names are detected and sorted in ascending lexicographic order at the installation.
If only one ethernet interface is detected (e.g. eth0
), it will be configured as follows:
eth0
) - Status: Enabled for WAN
- Configure: Using DHCP
If multiple ethernet interfaces are detected, instead, the first two interfaces will be configured as presented in the table below. The other ethernet interfaces will be disabled.
Interface Configuration First Ethernet interface (e.g.eth0
) - Status: Enabled for LAN
- Configure: Manually
- IP address: 172.16.0.1
- Router Mode: DHCP and NAT
Second Ethernet interface (e.g. eth1
) - Status: Enabled for WAN
- Configure: Using DHCP
Finally, if a wireless interface (e.g. wlan0
) is detected, it will configured as shown below. The other wireless interfaces will be disabled.
wlan0
) - Status: Enabled for LAN
- Configure: Manually
- IP address: 172.16.1.1
- Passphrase: testKEYS
- Router Mode: DHCP and NAT
For example, if the system contains the following interfaces: wlp2s0
, wlp3s0
, enp3s0
, eno1
, ens2
; then eno1
will be enabled for LAN with a DHCP server, enp3s0
will be enabled for WAN in DHCP client mode, wlp2s0
will be configured as an AP, and all other network interfaces will be disabled.
Warning
On systems that do not use systemd's predictable interface naming scheme (see Freedesktop reference) the primary network interface name might change whenever a re-enumeration is triggered (for example, after a reboot or after plugging in an external network adapter).
The advice is to install Kura on systems that use a reliable naming convention for network interfaces.
Systemd consistent network interface naming assigns the name prefix based on the physical location of the device, see Understanding the Predictable Network Interface Device Names for further reference.
"},{"location":"getting-started/install-kura/#initial-firewall-configuration","title":"Initial firewall configuration","text":"Similarly to the initial network configuration, the initial firewall setup is adapted based on the network interface detected on the system. In case of multiple ethernet and wireless interfaces, the configuration will be as shown in the screenshot below.
If the wireless interface is not present, the firewall entries for the wlan0
are dropped.
Please note that installing Eclipse Kura with network configuration support will replace the current network and firewall configuration with the one shown above.
"},{"location":"getting-started/install-kura/#other-kura-services","title":"Other Kura services","text":"Kura generic profiles do not contain gateway specific customizations, this implies that the values of some configuration parameters may be incorrect and/or missing and must be manually filled after installation. For example the user might want to:
/opt/eclipse/kura/framework/jdk.dio.properties
with the correct GPIO mappings. By default this file is empty.To have all the Kura features working, the following dependencies are required:
setserial
, zip
, gzip
, unzip
, procps
, usbutils
, socat
, gawk
, sed
, inetutils-telnet
.polkit
or policykit-1
, ssh
or openssh
, openssl
, busybox
, openvpn
.bluez
or bluez5
, bluez-hcidump
or bluez5-noinst-tools
.ntpdate
, chrony
, chronyc
, cron
or cronie
.network-manager
or networkmanager
, bind9
or bind
, dnsmasq
or isc-dhcp-server
or (dhcp-server
and dhcp-client
), iw
, iptables
, modemmanager
, hostapd
, wpa-supplicant
, ppp
, iproute2
.logrotate
.gpsd
.python3
.openjdk-17-jre-headless
or temurin-17-jdk
or openjdk-8-jre-headless
or temurin-8-jdk
.dos2unix
Kura generic has been tested on the following devices and provides full configuration of all the available interfaces and GPIO mappings.
Device Architecture OS Raspberry Pi 3/4 arm32 Raspbian \"Bookworm\" Raspberry Pi 3/4 arm64 Ubuntu 20.04 Intel Up\u00b2 x86_64 Ubuntu 20.04 NVIDIA Jetson Nano\u2122 arm64 Ubuntu 20.04Check out the quick start guides for the detailed installation steps and set-up procedures:
This section provides Eclipse Kura\u2122 quick installation procedures for the Intel Up\u00b2 and the Kura development environment.
Warning
This quickstart will install the version of Kura with the administrative web UI and network configuration support but not CAN bus support. For more information on this please visit the Eclipse Kura download page
This quickstart has been tested using the latest Ubuntu 20.04.3 LTS Live Server for amd64 architecture flashed on the SD card with balenaEtcher.
A complete guide on how to install Ubuntu on the Intel Up\u00b2 can be found here.
It is important, in order to access the HAT, Bluetooth, Wifi functionality, to follow the relative steps provided in the complete guide. Make sure to assign the right execute permissions to kurad
user created by the installer as described here.
Note
It is highly recommended to install the custom Intel kernel provided in the guide.
"},{"location":"getting-started/intel-up-2-quick-start/#eclipse-kuratm-installation","title":"Eclipse Kura\u2122 Installation","text":"To install Kura with its dependencies on the Intel Up\u00b2, perform the following steps:
Boot the Intel Up\u00b2 with the Ubuntu Image 20.04.3.
Make sure your device is connected to internet.
Upgrade the system:
sudo apt update\n
sudo apt upgrade\n
Tip
Optional: Since version 5.3.0 Kura also supports Eclipse Temurin\u2122 as an alternative JVM. To install it you need to perform these additional steps:
sudo apt-get install -y wget apt-transport-https gnupg\n
sudo wget -O - https://packages.adoptium.net/artifactory/api/gpg/key/public | sudo apt-key add -\n
sudo echo \"deb https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main\" | sudo tee /etc/apt/sources.list.d/adoptium.list\n
sudo apt-get update\n
sudo apt-get install temurin-17-jdk\n
Download the Kura package with:
wget http://download.eclipse.org/kura/releases/<version>/kura_<version>_intel-up2-ubuntu-20_installer.deb\n
Note: replace <version>
in the URL above with the version number of the latest release (e.g. 5.2.0).
Install Kura with:
apt-get install./ kura_<version>_intel-up2-ubuntu-20_installer.deb\n
Set the right Wi-Fi regulatory domain based on your current world region editing the /etc/default/crda
and adding the ISO 3166-1 alpha-2 code of your region.
Reboot the Intel Up\u00b2 with:
sudo reboot\n
Kura starts on the target platform after reboot.
Kura setups a local web ui that is available using a browser via:
https://<device-ip>\n
The browser will prompt the user to accept the connection to an endpoint with an untrusted certificate:
Once trusted the source, the user will be redirected to a login page where the default username is:
admin\n
and the default password is:
admin\n
This section provides Eclipse Kura\u2122 quick installation procedures for the NVIDIA Jetson Nano\u2122.
Warning
This quickstart will install the version of Kura with the administrative web UI and network configuration support but not CAN bus support. For more information on this please visit the Eclipse Kura download page
This quickstart has been tested using the latest Ubuntu 18.04 LTS image provided by NVIDIA here and burned on a SD card with Etcher.
The official images can be found on the Jetson Nano Developer Kit Getting Starteg Guide. Further information on the Ubuntu installation for the NVIDIA Jetson Nano\u2122 can be found here.
"},{"location":"getting-started/nvidia-jetson-nano-quick-start/#eclipse-kuratm-installation","title":"Eclipse Kura\u2122 Installation","text":"To install Eclipse Kura with its dependencies on the NVIDIA Jetson Nano\u2122, perform the following steps:
Boot the NVIDIA Jetson Nano\u2122 with the latest\u00a0Jetson Nano Developer Kit SD Card image.
Make sure your device is connected to internet. By default, eth0
lan network interface is configured in DHCP mode.
Upgrade the system:
sudo apt update\n
sudo apt upgrade\n
Tip
Optional: Since version 5.3.0 Kura also supports Eclipse Temurin\u2122 as an alternative JVM. To install it you need to perform these additional steps:
sudo apt-get install -y wget apt-transport-https gnupg\n
sudo wget -O - https://packages.adoptium.net/artifactory/api/gpg/key/public | sudo apt-key add -\n
sudo echo \"deb https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main\" | sudo tee /etc/apt/sources.list.d/adoptium.list\n
sudo apt-get update\n
sudo apt-get install temurin-17-jdk\n
Download the Kura package with:
wget http://download.eclipse.org/kura/releases/<version>/kura_<version>_nvidia-jetson-nano_installer.deb\n
Note: replace <version>
in the URL above with the version number of the latest release (e.g. 5.2.0).
Install Kura with:
sudo apt install ./kura_<version>_nvidia-jetson-nano_installer.deb\n
All the required dependencies will be downloaded and installed.
Reboot the NVIDIA Jetson Nano\u2122 with:
sudo reboot\n
Kura starts on the target platform after reboot.
Kura setups a local web ui that is available using a browser via:
https://<device-ip>\n
The browser will prompt the user to accept the connection to an endpoint with an untrusted certificate:
Once trusted the source, the user will be redirected to a login page where the following credentianls: username: admin
password: admin
This section provides Eclipse Kura\u2122 quick installation procedures for the Raspberry Pi and the Kura development environment.
Warning
This quickstart will install the version of Kura with the administrative web UI and network configuration support but not CAN bus support. For more information on this please visit the Eclipse Kura download page
This quickstart has been tested using the latest Raspberry Pi OS 32 and 64 bits images which are available for download through the official Raspberry Pi foundation site and the Raspberry Pi Imager.
Warning
Recent versions of Raspberry Pi OS 32 bit on Raspberry PI 4 will use by default a 64 bit kernel with a 32 bit userspace. This can cause issues to applications that use the result of uname -m
to decide which native libraries to load (see https://github.com/raspberrypi/firmware/issues/1795). This currently affects for example the Kura SQLite database connector. It should be possible to solve by switching to the 32 bit kernel setting arm_64bit=0
in /boot/config.txt
and restarting the device.
For additional details on OS compatibility refer to the Kura\u2122 release notes.
"},{"location":"getting-started/raspberry-pi-raspberryos-quick-start/#enable-ssh-access","title":"Enable SSH Access","text":"The ssh server is disabled by default on Raspbian images released after November 2016, in order to enable it follow the instructions available here.
If you're using the Raspberry Pi Imager you can directly enable SSH before writing the operating system into the SD card by clicking on the \"setting\" icon.
"},{"location":"getting-started/raspberry-pi-raspberryos-quick-start/#eclipse-kuratm-installation","title":"Eclipse Kura\u2122 Installation","text":"To install Eclipse Kura with its dependencies on the Raspberry Pi, perform the following steps:
Boot the Raspberry Pi with the latest\u00a0Raspbian image (starting from release 5.1.0 Kura is tested with Raspbian 11).
Make sure your device is connected to the internet. The best installation experience can be obtained when the device is cabled to the local network and the Internet. By default, the Raspberry Pi OS configures the ethernet interface eth0
in DHCP mode.
Upgrade the system:
sudo apt update\n
sudo apt upgrade\n
Tip
Optional: Since version 5.3.0 Kura also supports Eclipse Temurin\u2122 as an alternative JVM. To install it you need to perform these additional steps:
sudo apt-get install -y wget apt-transport-https gnupg\n
sudo wget -O - https://packages.adoptium.net/artifactory/api/gpg/key/public | sudo apt-key add -\n
sudo echo \"deb https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main\" | sudo tee /etc/apt/sources.list.d/adoptium.list\n
sudo apt-get update\n
sudo apt-get install temurin-17-jdk\n
Download the Kura package with:
wget http://download.eclipse.org/kura/releases/<version>/kura-<kura-version>_generic-<arch>_installer.deb\n
Note: replace <version>
in the URL above with the version number of the latest release (e.g. 5.5.0) and <arch>
with your device architecture
Install Kura with:\u00a0
sudo apt-get install ./kura-<kura-version>_generic-<arch>_installer.deb\n
For a correct configuration of the Wlan interface, it is necessary to set the Locale and the WLAN Country through the raspi-config
command:
sudo raspi-config\n
From the raspi-config main menu select Localisation Options
:
Then modify the Locale and WLAN Country with with the proper settings for your location. For example, an user located in Italy could set the values as the ones in the table:
Setting Value L1 Locale it_IT.UTF-8 UTF-8 L4 WLAN Country IT Italy(Optional) To correctly use the GPIO pins, the user is asked to update the jdk.dio.properties
file with the proper configuration, based on its own device.
This is required since the sysfs
interface has been deprecated, and some OS distribution may have already suppressed it. Moreover, the kernel complains if a static base number is assigned to a GPIO controller: indeed, when it assigns the numbers automatically, it usually starts from 511. More information can be found here.
In order to set the correct configuration the user can perform the following steps:
cat /sys/kernel/debug/gpio
, looking for entries similar to gpio-ABC (GPIxx)
: from this information it is possible to retrieve which number the GPIO controller was assigned to by the OS (in this case the GPIO controller number xx
is assigned with the number ABC
). The image below represent an example of this file/opt/eclipse/kura/framework/jdk.dio.properties
with the number and controllers found in the previous step:573 = deviceType: gpio.GPIOPin, pinNumber:573, name:GPI02\n574 = deviceType: gpio.GPIOPin, pinNumber:574, name:GPIO3\n575 = deviceType: gpio.GPIOPin, pinNumber:575, name:GPIO4\n576 = deviceType: gpio.GPIOPin, pinNumber:576, name:GPIO5\n577 = deviceType: gpio.GPIOPin, pinNumber:577, name:GPIO6\n578 = deviceType: gpio.GPIOPin, pinNumber:578, name:GPIO7\n579 = deviceType: gpio.GPIOPin, pinNumber:579, name:GPIO8\n580 = deviceType: gpio.GPIOPin, pinNumber:580, name:GPIO9\n581 = deviceType: gpio.GPIOPin, pinNumber:581, name:GPIO10\n582 = deviceType: gpio.GPIOPin, pinNumber:582, name:GPIO11\n583 = deviceType: gpio.GPIOPin, pinNumber:583, name:GPIO12\n584 = deviceType: gpio.GPIOPin, pinNumber:584, name:GPIO13\n585 = deviceType: gpio.GPIOPin, pinNumber:585, name:GPIO14\n586 = deviceType: gpio.GPIOPin, pinNumber:586, name:GPIO15\n587 = deviceType: gpio.GPIOPin, pinNumber:587, name:GPIO16\n588 = deviceType: gpio.GPIOPin, pinNumber:588, name:GPIO17\n589 = deviceType: gpio.GPIOPin, pinNumber:589, name:GPIO18\n590 = deviceType: gpio.GPIOPin, pinNumber:590, name:GPIO19\n591 = deviceType: gpio.GPIOPin, pinNumber:591, name:GPIO20\n592 = deviceType: gpio.GPIOPin, pinNumber:592, name:GPIO21\n593 = deviceType: gpio.GPIOPin, pinNumber:593, name:GPIO22\n594 = deviceType: gpio.GPIOPin, pinNumber:594, name:GPIO23\n595 = deviceType: gpio.GPIOPin, pinNumber:595, name:GPIO24\n596 = deviceType: gpio.GPIOPin, pinNumber:596, name:GPIO25\n597 = deviceType: gpio.GPIOPin, pinNumber:597, name:GPIO26\n598 = deviceType: gpio.GPIOPin, pinNumber:598, name:GPIO27\n\ngpio.GPIOPin = initValue:0, deviceNumber:0, direction:3, mode:-1, trigger:3\nuart.UART = baudRate:19200, parity:0, dataBits:8, stopBits:1, flowControl:0\n
You can also check your GPIO device configuration executing the command pinout
Reboot the Raspberry Pi with:
sudo reboot\n
Kura starts on the target platform after reboot.
Kura setups a local web ui that is available using a browser via:
https://<device-ip>\n
The browser will prompt the user to accept the connection to an endpoint with an untrusted certificate:
Once trusted the source, the user will be redirected to a login page where the following credentials: username: admin
password: admin
This section provides Eclipse Kura\u2122 quick installation procedures for the Raspberry Pi.
Warning
This quickstart will install the version of Kura with the administrative web UI and network configuration support but not CAN bus support. For more information on this please visit the Eclipse Kura download page
This quickstart has been tested using the latest Ubuntu 20.04.3 LTS Live Server for arm64 architecture flashed on the SD card through Raspberry Pi Imager.
The official images can be also found on the Project Page. Further information on the Ubuntu installation for Raspberry Pi can be found here.
Warning
Please note that, at the time of this writing, only 64 bit OS image is supported.
"},{"location":"getting-started/raspberry-pi-ubuntu-20-quick-start/#enable-ssh-access","title":"Enable SSH Access","text":"On Ubuntu 20.04.3 the ssh access is enabled only for the standard ubuntu user. If you desire to remote login as root user, edit the file /etc/ssh/sshd_config
(using the root permission) adding the line PermitRootLogin yes
To install Eclipse Kura with its dependencies on the Raspberry Pi, perform the following steps:
Boot the Raspberry Pi with the latest\u00a0Ubuntu 20.04.3 LTS Server image.
Make sure your device is connected to internet. By default, eth0
lan network interface is configured in DHCP mode.
Upgrade the system:
sudo apt update\n
sudo apt upgrade\n
Tip
Optional: Since version 5.3.0 Kura also supports Eclipse Temurin\u2122 as an alternative JVM. To install it you need to perform these additional steps:
sudo apt-get install -y wget apt-transport-https gnupg\n
sudo wget -O - https://packages.adoptium.net/artifactory/api/gpg/key/public | sudo apt-key add -\n
sudo echo \"deb https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main\" | sudo tee /etc/apt/sources.list.d/adoptium.list\n
sudo apt-get update\n
sudo apt-get install temurin-17-jdk\n
Download the Kura package with:
wget http://download.eclipse.org/kura/releases/<version>/kura-<kura-version>_generic-<arch>_installer.deb\n
Note: replace <version>
in the URL above with the version number of the latest release (e.g. 5.5.0) and <arch>
with your device architecture
Install Kura with:
sudo apt install ./kura-<kura-version>_generic-<arch>_installer.deb\n
All the required dependencies will be downloaded and installed.
Set the right Wi-Fi regulatory domain based on your current world region editing the /etc/default/crda
and adding the ISO 3166-1 alpha-2 code of your region.
(Optional) Configure the GPIO replacing the content of the file /opt/eclise/kura/framework/jdk.dio.properties
with the following text:
0 = deviceType: gpio.GPIOPin, pinNumber:0, name:GPIO0\n1 = deviceType: gpio.GPIOPin, pinNumber:1, name:GPIO1\n2 = deviceType: gpio.GPIOPin, pinNumber:2, name:GPI02\n3 = deviceType: gpio.GPIOPin, pinNumber:3, name:GPIO3\n4 = deviceType: gpio.GPIOPin, pinNumber:4, name:GPIO4\n5 = deviceType: gpio.GPIOPin, pinNumber:5, name:GPIO5\n6 = deviceType: gpio.GPIOPin, pinNumber:6, name:GPIO6\n7 = deviceType: gpio.GPIOPin, pinNumber:7, name:GPIO7\n8 = deviceType: gpio.GPIOPin, pinNumber:8, name:GPIO8\n9 = deviceType: gpio.GPIOPin, pinNumber:9, name:GPIO9\n10 = deviceType: gpio.GPIOPin, pinNumber:10, name:GPIO10\n11 = deviceType: gpio.GPIOPin, pinNumber:11, name:GPIO11\n12 = deviceType: gpio.GPIOPin, pinNumber:12, name:GPIO12\n13 = deviceType: gpio.GPIOPin, pinNumber:13, name:GPIO13\n14 = deviceType: gpio.GPIOPin, pinNumber:14, name:GPIO14\n15 = deviceType: gpio.GPIOPin, pinNumber:14, name:GPIO15\n16 = deviceType: gpio.GPIOPin, pinNumber:16, name:GPIO16\n17 = deviceType: gpio.GPIOPin, pinNumber:17, name:GPIO17\n18 = deviceType: gpio.GPIOPin, pinNumber:18, name:GPIO18\n19 = deviceType: gpio.GPIOPin, pinNumber:19, name:GPIO19\n20 = deviceType: gpio.GPIOPin, pinNumber:20, name:GPIO20\n21 = deviceType: gpio.GPIOPin, pinNumber:21, name:GPIO21\n22 = deviceType: gpio.GPIOPin, pinNumber:22, name:GPIO22\n23 = deviceType: gpio.GPIOPin, pinNumber:23, name:GPIO23\n24 = deviceType: gpio.GPIOPin, pinNumber:24, name:GPIO24\n25 = deviceType: gpio.GPIOPin, pinNumber:25, name:GPIO25\n26 = deviceType: gpio.GPIOPin, pinNumber:26, name:GPIO26\n27 = deviceType: gpio.GPIOPin, pinNumber:27, name:GPIO27\n\ngpio.GPIOPin = initValue:0, deviceNumber:0, direction:3, mode:-1, trigger:3\nuart.UART = baudRate:19200, parity:0, dataBits:8, stopBits:1, flowControl:0\n
Reboot the Raspberry Pi with:
sudo reboot\n
Kura starts on the target platform after reboot.
Kura setups a local web ui that is available using a browser via:
https://<device-ip>\n
The browser will prompt the user to accept the connection to an endpoint with a self signed certificate, select Accept the risk and continue
:
Once trusted the source, the user will be redirected to a login page where the following credentianls: username: admin
password: admin
This section provides a simple example of how to create an OSGi bundle that implements the ConfigurableComponent interface in Kura. This bundle will interact with the Kura ConfigurationService via the ConfigurableComponent interface. It also uses the MQTT services in Kura to connect to the Cloud, which allows for a local configuration mechanism using a Web user-interface (UI). In this example, you will learn how to perform the following functions:
Create a plugin project
Implement the ConfigurableComponent interface
Use the Kura web UI to modify the bundle\u2019s configuration
Export a single OSGi bundle (plug-in)
Requires Kura development environment set-up (Setting up Kura Development Environment)
Implements the use of Kura web user-interface (UI)
In Eclipse, create a new Plug-in project by selecting File | New | Project. Select Plug-in Development | Plug-in Project and click Next.
Your screen should display the New Plug-in Project dialog box as shown in the following screen capture. Enter your project a name, such as \u201corg.eclipse.kura.example.configurable\u201d. Under Target Platform, ensure that the an OSGi framework option button is selected and set to standard as shown below. You can also (optionally) add projects to a working set. To continue, click Next.
In the next New Plug-in Project menu (shown below), change the Name field to something more descriptive, such as \u201cConfigurable Component Example.\u201d Make sure that the Execution Environment list is set to match the JVM version running on the target device (JavaSE-1.6 or JavaSE-1.7). To determine the JVM version running on the target device, log in to its administrative console and enter the command
java \u2013version
Also, uncheck the Generate an activator, a Java class that controls the plug-in\u2019s life cycle option button. For the purposes of this example, a single class will be used. An Activator class will not be created; instead, OSGi Declarative Services will be used to start and stop the bundle.
Finally, click Finish.
You should see the new project in the Package Explorer (or Project Explorer) in Eclipse. Also, you will see the MANIFEST.MF was automatically opened in the Manifest Editor. An OSGi bundle is a regular Java .jar file that contains Java code and resources and a custom Manifest and an Activator. The manifest will be modified in the next section.
"},{"location":"java-application-development/configurable-application/#add-dependencies-to-manifest","title":"Add Dependencies to Manifest","text":"First, you will use the Manifest Editor in Eclipse to add some dependencies. Click the Dependencies tab at the bottom of the editor screen and then click the Automated Management of Dependencies heading to expand it.
Under Automated Management of Dependencies, click Add. In the Select a Plug-in field, enter org.eclipse.osgi.services. Select the plug-in name and click OK.
Note that this operation is very much like adding standalone jars to the buildpath by including the \u2018-cp\u2019 argument to javac. However, in this case you are telling Eclipse where to find these dependencies the \u201cOSGi way\u201d, so it is aware of them at compile time.
Click Add again and use the same procedure to add the following dependencies:
You should now see the list of dependencies. Save changes to the Manifest.
"},{"location":"java-application-development/configurable-application/#create-java-class","title":"Create Java Class","text":"Now you are ready to start writing a simple Java class. Right-click the org.eclipse.kura.example.configurable project. Select New | Class. Set the Package field to org.eclipse.kura.example.configurable, set the Name field to ConfigurableExample, and then click Finish.
Write the following code for the new class. You can copy and paste the code provided below into your newly created Java class file.
package org.eclipse.kura.example.configurable;\n\npublic class ConfigurableExample implements ConfigurableComponent {\n private static final Logger s_logger = LoggerFactory.getLogger(ConfigurableExample.class);\n private static final String APP_ID = \"org.eclipse.kura.example.configurable.ConfigurableExample\";\n private Map<String, Object> properties;\n\n protected void activate(ComponentContext componentContext) {\n s_logger.info(\"Bundle \" + APP_ID + \" has started!\");\n }\n\n protected void activate(ComponentContext componentContext, Map<String, Object> properties) {\n s_logger.info(\"Bundle \" + APP_ID + \" has started with config!\");\n updated(properties);\n }\n\n protected void deactivate(ComponentContext componentContext) {\n s_logger.info(\"Bundle \" + APP_ID + \" has stopped!\");\n }\n\n public void updated(Map<String, Object> properties) {\n this.properties = properties;\n if(properties != null && !properties.isEmpty()) {\n Iterator<Entry<String, Object>> it = properties.entrySet().iterator();\n while (it.hasNext()) {\n Entry<String, Object> entry = it.next();\n s_logger.info(\"New property - \" + entry.getKey() + \" = \" +\n entry.getValue() + \" of type \" + entry.getValue().getClass().toString());\n }\n }\n }\n}\n
The activate() method is the entry point when the bundle is started. Note this class has two forms of the activate() method. The second method (with the \u201cMap properties\u201d parameter) enables a default configuration to be specified at bundle start time. The deactivate() method is the entry point when the bundle is stopped. You have also specified an updated() method. These methods define how the bundle receives a new configuration from the Kura configuration manager. Kura handles robust configuration management routines automatically once you implement the ConfigurableComponent interface and the updated() method."},{"location":"java-application-development/configurable-application/#resolve-dependencies","title":"Resolve Dependencies","text":"
At this point, there will be errors in your code because of unresolved imports.
Select the menu Source | Organize Imports to resolve these errors. Because you added dependencies to your dependency list in the Manifest, you will be prompted to choose one of the following two potential sources for importing a few classes.
For the \u201cEntry\u201d class, select java.util.Map.Entry as shown below and click Next.
For the \u201cLogger\u201d class, select org.slf4j.Logger as shown below and click Finish.
Resolving the imports should clear the errors in the class as shown in the screen capture that follows. Save the changes to the ConfigurableExample class.
The complete set of code (with import statements) is shown below.
package org.eclipse.kura.example.configurable;\n\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\n\npublic class ConfigurableExample implements ConfigurableComponent {\n\n private static final Logger s_logger = LoggerFactory.getLogger(ConfigurableExample.class);\n private static final String APP_ID* = \"org.eclipse.kura.configurable.ConfigurableExample\";\n private Map<String, Object> properties;\n\n protected void activate(ComponentContext componentContext) {\n s_logger.info(\"Bundle \" + APP_ID + \" has started!\");\n }\n\n protected void activate(ComponentContext componentContext, Map<String, Object> properties) {\n s_logger.info(\"Bundle \" + APP_ID + \" has started with config!\");\n updated(properties);\n }\n\n protected void deactivate(ComponentContext componentContext) {\n s_logger.info(\"Bundle \" + APP_ID + \" has stopped!\");\n }\n\n public void updated(Map<String, Object> properties) {\n this.properties = properties;\n if(properties != null && !properties.isEmpty()) {\n Iterator<Entry<String, Object>> it = properties.entrySet().iterator();\n while(it.hasNext()) {\n Entry<String, Object> entry = it.next();\n s_logger.info(\"New property - \" + entry.getKey() + \" = \" +\n entry.getValue() + \" of type \" + entry.getValue().getClass().toString());\n }\n }\n }\n}\n
Switch back to the Manifest Editor. Under Automated Management of Dependencies, ensure the Import-Package option button is selected. Click the add dependencies link to automatically add packages to the dependencies list (under Imported Packages) based on the \u201cimport\u201d statements in your example code. Save changes to the Manifest again.
"},{"location":"java-application-development/configurable-application/#create-component-class","title":"Create Component Class","text":"Right-click the example project and select New | Folder. Create a new folder named \u201cOSGI-INF\u201d.
Now, right-click the example project\u2019s \u201cOSGI-INF\u201d folder and select New | Other. From the wizard, select Plug-in Development | Component Definition and click Next.
Next to the Class field, click Browse and type the name of your newly created class in the Select entries field. In this case, type the word \u201cConfigurable\u201d, and you will see matching items. Select the ConfigurableExample class and click OK.
In the Enter or select the parent folder field, make sure \u201c/OSGI-INF\u201d is at the end of the existing entry (e.g., org.eclipse.kura.example.configurable/OSGI-INF). Set the Name field equal to the Class field as shown below:
Click Finish.
After the Component class has been created, it will open in the Workspace. On the Services tab, click the Add button under Provided Services. Enter \u201cconfigurable\u201d and select the interface \u201corg.eclipse.kura.example.configurable\u201d. This is required for components that are configurable through the Kura ConfigurationService, so that they expose a Service.
In the Overview tab, the Name and Class fields should already point to your Java class. Make the following settings:
Set the Activate field to activate and set the Deactivate field to deactivate. This tells the component where these OSGi activation methods are located.
Set the Configuration Policy to require.
Set the Modified field to updated. This tells the component which method to call when the configuration is updated.
Uncheck the box This component is enabled when started, then check both boxes This component is enabled when started and This component is immediately activated.
Click the Add Property button. Enter a property with the name \u201cservice.pid\u201d and value \u201corg.eclipse.kura.example.configurable.ConfigurableExample\u201d as shown in the screen capture below.
Verify that the completed Overview tab looks like the screen shot shown below and save the Component class definition file:
Check the Source tab of the component.xml file and carefully verify that each of the property values and tags match what is shown below:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\"\n activate=\"activate\"\n configuration-policy=\"require\"\n deactivate=\"deactivate\"\n enabled=\"true\"\n immediate=\"true\"\n modified=\"updated\"\n name=\"org.eclipse.kura.example.configurable.ConfigurableExample\">\n\n <implementation class=\"org.eclipse.kura.example.configurable.ConfigurableExample\"/>\n <service>\n <provide interface=\"org.eclipse.kura.example.configurable.ConfigurableExample\"/>\n </service>\n <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.example.configurable.ConfigurableExample\"/>\n</scr:component>\n
If Kura 3.0 or newer versions are used and the \"org.eclipse.kura.core.configuration.legacyServiceTracking\" system property is set to false or not set, proceed as follows.
"},{"location":"java-application-development/configurable-application/#create-the-default-configuration","title":"Create the Default Configuration","text":"With the component definition file created, you also need to specify the configurable parameters of this bundle. This is done using the \u201cmetatype\u201d definition. Right-click the OSGI-INF directory for the example project in the Package Explorer window and select New | Folder. Name the folder \u201cmetatype\u201d. Next, right-click the metatype folder and select New | File.
Name the file \u201corg.eclipse.kura.example.configurable.ConfigurableExample.xml\u201d as shown in the following screen capture:
At this point, you have to write the \u2018metatype\u2019 file that defines the parameters, default values, types, etc. Click on the Source button and paste the following XML text into ConfigurableExample.xml for this example. Save changes to ConfigurableExample.xml.
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n <OCD id=\"org.eclipse.kura.example.configurable.ConfigurableExample\"\n name=\"ConfigurableExample\"\n description=\"This is a sample metatype file for a simple configurable component\">\n\n <AD id=\"param1.string\"\n name=\"param1.string\"\n type=\"String\"\n cardinality=\"0\"\n required=\"true\"\n default=\"Some Text\"\n description=\"String configuration parameter\"/>\n\n <AD id=\"param2.float\"\n name=\"param2.float\"\n type=\"Float\"\n cardinality=\"0\"\n required=\"false\"\n default=\"20.5\"\n min=\"5.0\"\n max=\"40.0\"\n description=\"Float configuration parameter\"/>\n\n <AD id=\"param3.integer\"\n name=\"param3.integer\"\n type=\"Integer\"\n cardinality=\"0\"\n required=\"true\"\n default=\"2\"\n min=\"1\"\n description=\"Integer configuration parameter\"/>\n </OCD>\n\n <Designate pid=\"org.eclipse.kura.example.configurable.ConfigurableExample\">\n <Object ocdref=\"org.eclipse.kura.example.configurable.ConfigurableExample\"/>\n </Designate>\n</MetaData>\n
In the MANIFEST.MF of this bundle, you must also make sure the XML file gets packaged into the bundle when you export the plug-in. Click the Build tab, and in the Binary Build section of the Manifest editor verify that all the checkboxes for items under META-INF and OSGI-INF are checked. Save the Manifest after making this change.
"},{"location":"java-application-development/configurable-application/#run-the-bundle","title":"Run the Bundle","text":"At this point, you can run the bundle using the emulator in Eclipse (Linux or OS X only). To do so, expand the org.eclipse.kura.emulator project in the package explorer and browse to src/main/resources. As appropriate for you platform type, right-click Kura_Emulator_[OS].launch (where \u201c[OS]\u201d specifies your operating system) and select Run as | KURA_EMULATOR_[OS].launch. Doing so will start the Kura emulator and your new bundle in the console window of Eclipse.
"},{"location":"java-application-development/configurable-application/#view-the-bundle-configuration-in-the-local-web-ui","title":"View the Bundle Configuration in the Local Web UI","text":"With the bundle running, open a browser window on the same computer as the Eclipse development environment and browse to the Kura web UI at http://127.0.0.1:8080. Once connected to the Kura web UI, a log in window appears prompting you to enter the Name and Password as shown below:
Enter the appropriate name and password (default is admin/admin) and click Log in. The Kura Admin web UI appears with the ConfigurableExample in the Services area on the left side of the browser window as shown below:
From the Kura Admin web UI, you can change the parameters that are used by the Kura configuration manager and in turn call the updated() method of the newly created bundle. To do so, click ConfigurableExample and the configurable component parameters will be displayed as shown below:
Make any necessary changes and click the Apply button near the top left of the configuration pane for the modifications to take affect. Every time a change is made to the configuration, a new snapshot is generated along with an ID.
"},{"location":"java-application-development/connected-application/","title":"Connected Application","text":""},{"location":"java-application-development/connected-application/#overview","title":"Overview","text":"This section describes the prepackaged heater demo bundle that comes with the Kura development environment and demonstrates how to perform the following functions:
Run the Kura Emulator
Connect to the Cloud
Gain an understanding of ConfigurableComponents in Kura
Modify configurations of custom bundles
Setting up Kura Development Environment
Using the Kura web UI
The org.eclipse.kura.demo.heater bundle is a simple OSGi bundle that represents a thermostat and heater combination. The application utilizes the Kura ConfigurableComponent interface to be able to receive configuration updates through the local Kura web UI. In addition, this bundle utilizes OSGi declarative services and the Kura CloudClientListener. This tutorial demonstrates how to modify configurations of custom bundles and shows how those configuration changes can dynamically impact the behavior of the bundle through the Kura web UI.
"},{"location":"java-application-development/connected-application/#code-walkthrough","title":"Code Walkthrough","text":"The following sections will highlight three important API layers when creating an application that will publish to the cloud. These layers are:
The CloudService can manage multiple applications over a shared MQTT connection by treating each application as a client. The example code uses the \"setCloudService\" and \"unsetCloudService\" methods for referencing and releasing the CloudService. In the bundles activate method, the service reference in conjunction with a unique application ID can then be used to obtain a CloudClient. The relevant code is shown below (ommitted sections are denoted by ==OMMITTED==):
==OMMITTED==\n// Cloud Application identifier\nprivate static final String APP_ID = \"heater\";\n\n==OMMITTED==\n\npublic void setCloudService(CloudService cloudService) {\n m_cloudService = cloudService;\n}\n\npublic void unsetCloudService(CloudService cloudService) {\n m_cloudService = null;\n}\n\n==OMMITTED==\n\n// Acquire a Cloud Application Client for this Application\ns_logger.info(\"Getting CloudClient for {}...\", APP_ID);\nm_cloudClient = m_cloudService.newCloudClient(APP_ID);\n
"},{"location":"java-application-development/connected-application/#publishingsubscribing","title":"Publishing/Subscribing","text":"The private \"doPublish\" method is used to publish messages at a fixed rate. The method demonstrates how to use the CloudClient and KuraPayload to publish MQTT messages.
==OMMITTED==\n\n// Allocate a new payload\nKuraPayload payload = new KuraPayload();\n\n// Timestamp the message\npayload.setTimestamp(new Date());\n\n// Add the temperature as a metric to the payload\npayload.addMetric(\"temperatureInternal\", m_temperature);\npayload.addMetric(\"temperatureExternal\", 5.0F);\npayload.addMetric(\"temperatureExhaust\", 30.0F);\n\nint code = m_random.nextInt();\nif ((m_random.nextInt() % 5) == 0) {\n payload.addMetric(\"errorCode\", code);\n}\nelse {\n payload.addMetric(\"errorCode\", 0);\n}\n\n// Publish the message\ntry {\n m_cloudClient.publish(topic, payload, qos, retain);\n s_logger.info(\"Published to {} message: {}\", topic, payload);\n}\ncatch (Exception e) {\n s_logger.error(\"Cannot publish topic: \"+topic, e);\n}\n
Similarly, the CloudClient can be used to subscribe to MQTT topics. Although not shown in the example code, the following snippet could be added to subscribe to all published messages:
m_cloudClient.subscribe(topic, qos);\n
"},{"location":"java-application-development/connected-application/#callback-methods","title":"Callback Methods","text":"The example class implements CloudClientListener, which provides methods for several common callback methods. The below snippet shows the relevant code for creating the listeners for the demo application.
==OMMITTED==\n\npublic class Heater implements ConfigurableComponent, CloudClientListener\n\n==OMMITTED==\n\nm_cloudClient.addCloudClientListener(this);\n
The available methods for implementation are:
For more information on the various Kura APIs, please review the Kura APIs
"},{"location":"java-application-development/connected-application/#run-the-bundle","title":"Run the Bundle","text":"By default, the heater demo bundle does not run automatically. To run the bundle and Kura in the Emulator, locate the org.eclipse.kura.emulator project. Expand it to show the src/main/resources folder.
Right-click the correct Kura_Emulator_[OS].launch file, depending on which operating system you are running. In the context menu, select the Run As option, and click on Run Configurations.
Under OSGi Framework (Run Configurations window shown below), click on the Kura_Emulator_[OS] entry. In the Bundles tab under Workspace, enable the org.eclipse.kura.demo.heater checkbox to enable it as shown below:
Click the Apply and Run buttons to start the Kura Emulator. Once this setting has been made, you only need to right-click on the launch file and select Run As and the Kura_Emulator_[OS] option to run with the same settings.
This will start Kura running locally and will display a Console window in Eclipse. The Console window will show the OSGi diagnostics as various bundles start and execute.
"},{"location":"java-application-development/connected-application/#configure-the-mqtt-client","title":"Configure the MQTT Client","text":"With the heater demo bundle running, open a browser window on the same computer as the Eclipse development environment and browse to the Kura web UI at http://127.0.0.1:8080. Once connected to the Kura web UI, a log in window appears prompting you to enter the Name and Password as shown below:
Enter the appropriate name and password (default is admin/admin) and click Log in. The Kura Admin web UI appears as shown below:
From the Kura web UI, click on MqttDataTransport in the Services pane on the lower left of the browser window. You will see a menu similar to the one shown in the following screen capture:
Fill in the following fields then click the Apply button:
Field Value broker-url: The url for the MQTT broker (this example shows the MQTT broker-url mqtt://iot.eclipse.org:1883/ hosted by the Eclipse Foundation) topic.context.account-name: Your [account_name] username: Typically [account_name]_broker password: The password for your user client-id The client identifier to be used when connecting to the MQTT broker (optional)Now that the account credentials are set in the MqttDataTransport service, the DataService needs to be configured to connect by default. To do so, click DataService in the Services area on the left of the browser window. For the \u2018connect.auto-on-startup\u2019 parameter, select true as shown below:
"},{"location":"java-application-development/connected-application/#modify-bundle-configuration-in-local-web-ui","title":"Modify Bundle Configuration in Local Web UI","text":"Bundles changes may be made directly in the emulator web UI. Since you are running an emulated device in Eclipse, you can do this by browsing to http://127.0.0.1:8080 (same URL where the MQTT client was configured in the previous section of this tutorial). If the bundle was running on a real device and you had network access to it, you would browse to http://[ip_address_of_device].
From the Kura web UI, select the Heater bundle from the configurable services on the left and modify the parameters as needed (shown in the screen capture below). By default, the heater demo is configured according to the following characteristics and assumptions about its operational environment:
Start operation is at 6:00am (06:00).
End operation is at 10:00pm (22:00).
It is colder outside than inside the heated chamber (hard-coded to 5 degrees in the application).
Output of the heater is constant at 30 degrees (hard-coded).
When in operational mode, the temperature will drop inside if the heater is off.
The heater turns off when it is about to exceed the setPoint defined in the configuration.
After the temperature drops to four times the increment point (a made-up value to show dropping temperature, hard-coded in the application), the heater turns back on, and the temperature starts increment at the rate of the \u2018temperature.increment\u2019 rate.
Click Apply for changes to take affect. The updated() method is called after settings are applied for the new configuration.
After completing this tutorial, it is highly recommended that you review the heater demo source code in Eclipse to see how it is put together. Kura automatically generates the user configuration interface through implementation of the ConfigurableComponent interface and some small additions to the component.xml file (called heater.xml). This powerful feature provides both a local and remote configuration user interface with no additional development requirements.
"},{"location":"java-application-development/contributing/","title":"Contributing","text":"Contributing to Eclipse Kura project is very easy.
The steps required to submit code to the project can be found on Github Contributing Page.
If you face any issues, or just want to get involved with the kura community feel free to join us on:
If you want to get involved in the development process you can join us at the Kura Dev Meeting. The meeting is held every 2 weeks on Wednesday, at 5 PM CEST on Microsoft Teams.
You can join by using this link.
The scheduled dates for the meeting can be found here. Unzip the calendar file and double-click on it to add the scheduled dates to your calendar.
"},{"location":"java-application-development/deploy-and-debug-applications/","title":"Deploy and Debug Applications","text":""},{"location":"java-application-development/deploy-and-debug-applications/#overview","title":"Overview","text":"This section provides a simple example of how to test and deploy OSGi bundles and deployment packages in a Kura environment. These instructions use the \u201cHello World\u201d OSGi project created in the previous section. In this example, you will learn how to perform the following functions:
Use local OSGi emulation mode in Eclipse
Deploy a bundle to a remote target running the OSGi Framework
Install a Deployment Package to a remote target running the OSGi Framework
Manage OSGi bundles on a target device
Set bundle Logger levels in Kura
Setting up Kura Development Environment
Hello World Using the Kura Logger
Once you have created an OSGi plug-in, you can test it in Local Emulation Mode and/or deploy it to a Remote Target Device.
"},{"location":"java-application-development/deploy-and-debug-applications/#local-emulation-mode","title":"Local Emulation Mode","text":"The Kura user workspace can be used in Eclipse in local emulation mode (Linux/OS X only; this feature is not currently supported under Windows). To deploy the code to a running system, see the section Remote Target Device.
"},{"location":"java-application-development/deploy-and-debug-applications/#run-kura-in-emulator-mode","title":"Run Kura in Emulator Mode","text":"In the Eclipse workspace, locate the org.eclipse.kura.emulator project. Expand it to show the src/main/resources folder.
Right-click the Kura_Emulator.launch file. In the context menu, select the Run as option, and select the Kura_Emulator*. This will start Kura running locally and will display a Console window in the bottom pane in Eclipse. The Console window will show the OSGi diagnostics as various bundles start and execute.
Because the org.eclipse.kura.example.hello_osgi bundle is in the workspace with a valid activate() method, it is automatically started with the Kura OSGi framework. Note the INFO message highlighted below that shows the bundle\u2019s activate() method was run.
"},{"location":"java-application-development/deploy-and-debug-applications/#list-osgi-bundles-in-local-mode","title":"List OSGi Bundles in Local Mode","text":"With the OSGi framework running in the Eclipse console (refer to the previous section), click in the Console window. Press Enter/Return and then type the \u2018ss\u2019 command to show a list of installed bundles. Note the bundle ID number for the org.eclipse.kura.example.hello_osgi bundle.
"},{"location":"java-application-development/deploy-and-debug-applications/#startstop-bundle-in-local-mode","title":"Start/Stop Bundle in Local Mode","text":"In the OSGi Console window in Eclipse, run the
start ##
or stop ##
commands to start or stop a bundle, where the \u201c##\u201d is either the bundle ID number or the bundle name (such as \u201cstart org.eclipse.kura.example.hello_osgi\u201d). Note that the INFO messages for both the activate() and deactivate() messages appear in the Console window when the bundle is started or stopped.
"},{"location":"java-application-development/deploy-and-debug-applications/#installuninstall-bundle-in-local-mode","title":"Install/Uninstall Bundle in Local Mode","text":"In the OSGi Console window in Eclipse, bundles can be installed or uninstalled. To uninstall the example bundle, issue the command \u2018uninstall ##\u2019, where \u201c##\u201d is either the bundle ID number or the bundle name, such as:
uninstall 47
or uninstall org.eclipse.kura.example.hello_osgi
A message will appear indicating that the bundle has been stopped.
Once the bundle has been uninstalled from the local OSGi console, it cannot be started or installed by number or name. Instead, it must be installed by using the plug-in JAR file created earlier. Issue the \u2018install\u2019 command to install a bundle into the Emulation environment:
install file:/[*path_to_bundle*]/[*bundle_name*].jar
where \u201c[path_to_bundle]/[bundle_name].jar\u201d should be replaced with the name of the bundle exported earlier (the section Hello World Using the Kura Logger), as shown in the example below:
install file:/Users/Nina/Documents/myPlugins/plugins/plugins/plugins/plugins/plugins/org.eclipse.kura.example.hello_osgi_ 1.0.0.201409101740.jar
Then the bundle can be started or stopped, as described in the previous section, Start/Stop Bundle in Local Mode. Optionally, you can add the flag \u2018-start\u2019 to the \u2018install\u2019 command to automatically start the bundle after installation.
"},{"location":"java-application-development/deploy-and-debug-applications/#remote-target-device","title":"Remote Target Device","text":"One or more OSGi bundles can be deployed to a remote device running Kura, either by installing separate bundle files or deployment packages using Eclipse.
Warning
These steps require Kura to be running on the target device.
This method of deployment is temporary on the remote target device and is not persistent after a restart. To make the deployment permanent, see Making Deployment Permanent.
"},{"location":"java-application-development/deploy-and-debug-applications/#connect-to-remote-osgi-framework","title":"Connect to Remote OSGi Framework","text":"To deploy a bundle to the remote target device, you will need to connect Eclipse to the OSGi framework running on the device. This is done using mToolkit. See Kura Setup for instructions on installing mToolkit into the Eclipse development environment.
Select the Eclipse menu Window | Show View | Other.
Select mToolkit -> Frameworks entry to open the mToolkit Frameworks view.
Enter a name for the framework definition and the IP address of the target device.
Close the dialog by clicking the OK button.
Warning
The remote target device must have port 1450 open in its firewall, in order to allow mToolkit o make a connection to its OSGi framework. If this port is not opened, refer to the section Open Port for OSGi Remote Connection.
Right-click the framework icon name and select Connect Framework. The list of installed bundles and deployment packages should be retrieved shortly. (Use the Disconnect Framework option to disconnect from the remote target framework when finished.)
"},{"location":"java-application-development/deploy-and-debug-applications/#open-port-for-osgi-remote-connection","title":"Open Port for OSGi Remote Connection","text":"In order to allow mToolkit to make a remote connection to the OSGi framework on the target device, the device must allow the incoming port in its firewall. To set this option, open a Web browser and log into Kura using its current IP address, such as:
http://10.11.5.4
Click the Firewall icon and then click the Open Ports tab. If port 1450 is not shown in the list of allowed ports, click the New button under Open Ports. Enter the port 1450 and select protocol TCP. Then click Submit.
Now, click Apply to apply changes to the remote device.
"},{"location":"java-application-development/deploy-and-debug-applications/#install-single-bundle-to-target-device","title":"Install Single Bundle to Target Device","text":"With the Eclipse environment connected to the remote OSGi target framework, a single bundle can be installed on the remote device.
In the mToolkit Frameworks view, right-click the Framework name and select Install Bundle. (This requires that you have exported the bundle as a deployable plug-in JAR file. See the section Hello World Using the Kura Logger.)
Use the Browse button to select the JAR file and click OK to install it to the target device.
The newly installed bundle should be shown in the Frameworks view under Bundles.
To control operation of the bundle through the OSGi Frameworks view, right-click the bundle name. The following actions can be performed:
Start \u2013 start the bundle
Stop \u2013 stop the bundle
Update \u2013 reinstall the bundle
Install Bundle \u2013 install a different bundle
Uninstall Bundle \u2013 remove this bundle from the target device
Show Bundle IDs / Show Bundle Versions \u2013 show additional information about bundles
You can also verify operation of the bundle on the target device itself. See the section Manage Bundles on Target Device.
"},{"location":"java-application-development/deploy-and-debug-applications/#install-deployment-package-to-target-device","title":"Install Deployment Package to Target Device","text":"With the Eclipse environment connected to the remote OSGi target framework, a deployment package can be installed on the remote device.
NOTE: If you have just installed the individual bundle in the previous section, you should uninstall it before proceeding. Doing so will avoid any confusion in having the same bundle installed twice.
In the mToolkit Frameworks view, right-click the Framework name and select Install Deployment Package. (This step requires that you have exported the bundle as a deployable plug-in JAR file. See the section Hello World Using the Kura Logger for instructions on exporting the OSGi bundle.)
Open the resources/dp folder in the Workspace filesystem directory, select the .dp file (not the \u201c.dpp\u201d file), and click OK.
The deployment package will be installed on the target device and shown in the Frameworks view under Deployment Packages. (The deployment package can also be uninstalled from the Framework view.)
The bundle included in the deployment package can also be viewed under Bundles and can be controlled remotely (start/stop) as with other bundles. The operation of the bundle can also be verified on the target device itself. See the section Manage Bundles on Target Device.
"},{"location":"java-application-development/deploy-and-debug-applications/#connect-to-osgi-on-target-device","title":"Connect to OSGi on Target Device","text":"You can manage the OSGi framework on a target device by logging into a console on the device using a connected keyboard and VGA monitor or over a network connection using SSH (PuTTY in Windows or \u2018ssh\u2019 from Linux or Mac).
At the command prompt, display the Kura log file with:
tail -f /var/log/kura.log
Connect to the OSGi framework by typing the following commands:
telnet localhost 5002
There are many commands available in the OSGi console for managing bundles. Following are just a few useful commands:
Command Description ss Lists names and ID of bundles help Displays the help menu of OSGi commands lb Lists all installed bundles and IDs h [bundle IDs] Displays bundle headers (i.e., Bundle Manifest Version, Name, Required Execution Environment, Symbolic Name, Version, Import Package, Manifest Version, and Service Component) exit Exits the OSGi console and stops Kura disconnect Exits the OSGi console, but leaves Kura running"},{"location":"java-application-development/deploy-and-debug-applications/#manage-bundles-on-target-device","title":"Manage Bundles on Target Device","text":"From the OSGi command line, you can display a list of bundles with the \u2018ss\u2019 command as shown in the example below:
ss
In this example, the org.eclipse.kura.example.hello_osgi bundle ID is 64.
You can run the \u2018start ##\u2019 or \u2018stop ##\u2019 commands to start or stop a bundle, where the \u201c##\u201d is either the bundle ID number or the bundle name (such as \u201cstart org.eclipse.kura.example.hello_osgi\u201d). To verify that the bundled is stopped, you can issue the \u2018ss\u2019 command. If the bundled is stopped, the activity will show RESOLVED (as shown below). If the bundle is started, the activity will show ACTIVE (as shown above).
"},{"location":"java-application-development/deploy-and-debug-applications/#set-kura-logger-levels","title":"Set Kura Logger Levels","text":"Kura logger levels are defined in a configuration file. The messages that appear require a log statement in the application and that the log level of the statement matches the log level of the application (such as logger.info or logger.debug).
To set or change logger levels, the Kura logger configuration file may be modified using the vi editor. From the Linux command prompt, enter the following command:
vi /opt/eclipse/kura/kura/log4j.properties
At the bottom of the \u201clog4j.properties\u201d file, there will be one or more \u201clog4j\u201d logger property entries, which determine the logger level used by the bundles at startup.
In the example screen capture shown below, the \u201clog4j.logger.org.eclipse.kura\u201d property has been set to \u201cINFO\u201d, which applies to all bundles that start with \u201corg.eclipse.kura.\u201d Additional, more specific, properties may be defined as required for your particular logging needs. The property entries will take on the defined logger level at startup. The logger levels are hierarchical, so that those in a deeper level of the hierarchy will apply; otherwise, the more general logger level will override them.
Once you have made the necessary changes, save and close the file using the \u2018:wq\u2019 command. Restart Kura, and check the log levels in the OSGi console again to make sure that the desired levels have taken effect.
"},{"location":"java-application-development/deploy-and-debug-applications/#making-deployment-permanent","title":"Making Deployment Permanent","text":"The mToolkit deployment of a package is a temporary installation and does not make the package permanent. Once a set of bundles has been tested on the remote target device and is ready for permanent deployment, the software can be installed on a device with deployment packages from the command line of a target device using the instructions below:
/opt/eclipse/kura/kura/packages
vi /opt/eclipse/kura/kura/dpa.properties
package_name=file\\:/opt/eclipse/kura/kura/packages/package_filename.dp
where, \u201cpackage_name\u201d and \u201cpackage_filename\u201d should be replaced with the actual name of the deployment package.
Save and close the file using the \u2018:wq\u2019 command.
Then restart Kura, and the new package should be installed in addition to the default Kura package.
In conclusion, this section described how to test a bundle in an Emulation environment within the Eclipse IDE and how to install bundles and Deployment Packages to a remote target system running Kura.
"},{"location":"java-application-development/development-environment-setup/","title":"Development Environment Setup","text":"In this document we'll cover the required steps to setup the Development Environment for contributing to the Eclipse Kura project. If, instead, you want to develop applications or bundles running on Eclipse Kura refer to the Eclipse Kura Workspace setup guide.
The Eclipse Kura development environment may be installed on Windows, Linux, or Mac OS. The setup instructions will be the same across each OS though each system may have unique characteristics.
Info
The local emulation of Eclipse Kura code is only supported in Linux and Mac, not in Windows.
This document will cover the use of Eclipse Oomph installer which is the easiest way to install and configure the Eclipse IDE to start contributing to Eclipse Kura.
The setup requires three basic steps:
Before building Eclipse Kura, you need to have the following programs installed in your system:
Recommended additional software:
To install Java 8, download the JDK tar archive from the Adoptium Project Repository.
Once downloaded, copy the tar archive in /Library/Java/JavaVirtualMachines/
and cd into it. Unpack the archive with the following command:
sudo tar -xzf <archive-name>.tar.gz\n
The tar archive can be deleted afterwards. Depending on which terminal you are using, edit the profiles (.zshrc, .profile, .bash_profile) to contain:
# Adoptium JDK 8\nexport JAVA_8_HOME=/Library/Java/JavaVirtualMachines/<archive-name>/Contents/Home\nalias java8='export JAVA_HOME=$JAVA_8_HOME'\njava8 \n
Reload the terminal and run java -version
to make sure it is installed correctly. Using Brew you can easily install Maven from the command line:
brew install maven@3.5\n
Run mvn -version
to ensure that Maven has been added to the PATH. If Maven cannot be found, try running brew link maven@3.5 --force
or manually add it to your path with: export PATH=\"/usr/local/opt/maven@3.5/bin:$PATH\"\n
"},{"location":"java-application-development/development-environment-setup/#installing-prerequisites-in-linux","title":"Installing Prerequisites in Linux","text":"For Java
sudo apt install openjdk-8-jdk\n
For Maven
You can follow the tutorial from the official Maven site. Remember that you need to install 3.5.x version or greater.
"},{"location":"java-application-development/development-environment-setup/#eclipse-oomph-setup","title":"Eclipse Oomph setup","text":"Download the latest Eclipse Installer appropriate for your platform from the Eclipse Downloads page and start it.
Switch to \"Advanced Mode\" (top right hamburger menu) and select \"Eclipse IDE for Eclipse Committers\" and configure the \"Product Version\" to be the version 2023-03 or newer.
Select the Eclipse Kura installer from the list. If this is not available, add a new installer from https://raw.githubusercontent.com/eclipse/kura/develop/kura/setups/kura.setup, then check and press the \"Next\" button.
Variables setup
JRE 1.8 location
value to the installed local jdk-8 VMIf you plan to contribute to Eclipse Kura you might want to create a fork, see our contributing guide for further informations. For the purpose of this tutorial we'll work with a fictional fork for the username user
. To clone the repo use the link appropriate for your fork, in our case it will be: https://github.com/user/kura.git
Keep in mind that the \"Root install folder\" is where the Eclipse executable will be installed and the Eclipse Kura sources will be downloaded (in the git
subfolder).
Press Next, leave all Bootstrap Tasks selected and press the Finish button
Accept all the licenses and wait for the installation to finish.
At first startup Eclipse IDE will checkout the code, perform a full build and configure a few Working Sets
When the tasks are completed, go to into the Package Explorer and Target Platform > Target-Definition > Kura Target Platform Equinox 3.16.0, and press \"Set as Target Platform\" located at the top right of the window:
"},{"location":"java-application-development/development-environment-setup/#eclipse-kura-maven-build","title":"Eclipse Kura maven build","text":"Navigate to the git
folder created within the Eclipse workspace (~/iot-kura-workspace
in the example above) and build the target platform:
mvn -f target-platform/pom.xml clean install\n
Then build the core components:
mvn -f kura/pom.xml clean install\n
Build the examples (optional):
mvn -f kura/examples/pom.xml clean install\n
Build the target profiles:
mvn -f kura/distrib/pom.xml clean install -DbuildAll\n
Note
You can skip tests by adding -Dmaven.test.skip=true
in the commands above and you can compile a specific target by specifying the profile (e.g. -Praspberry-pi-armhf
).
Alternatively you can use the build scripts available in the root directory.
./build-all.sh\n
or
./build-menu.sh\n
and select the profiles you want to build.
"},{"location":"java-application-development/hello-world-application/","title":"Hello World Application","text":""},{"location":"java-application-development/hello-world-application/#overview","title":"Overview","text":"This section provides a simple example of how to create a Kura \u201cHello World\u201d OSGi project using Eclipse. With this example, you will learn how to perform the following functions:
Create a plugin project
Consume the Kura Logger service
Write an OSGi Activator
Export a single OSGi bundle (plug-in)
Create a Deployment Package
Setting up the Kura Development Environment
"},{"location":"java-application-development/hello-world-application/#hello-world-using-the-kura-logger","title":"Hello World Using the Kura Logger","text":""},{"location":"java-application-development/hello-world-application/#create-hello-world-plug-in","title":"Create Hello World Plug-in","text":"In Eclipse, create a new Plug-in project by selecting File | New | Project. Select Plug-in Development | Plug-in Project and click Next.
Your screen should display the New Plug-in Project dialog box as shown in the following screen capture. Enter your project a name, such as \u201corg.eclipse.kura.example.hello_osgi\u201d, in the appropriate field. Under Target Platform, ensure that the an OSGi framework option button is selected and set the variable to standard as shown below. You can also (optionally) add projects to a working set. To continue, click Next.
In the next New Plug-in Project menu (shown below), change the Name field to a descriptive name, such as \u201cHello World Example with Logger\u201d.
Also, verify that the Execution Environment list is set to match the Java JVM version running on the target device (JavaSE-1.8 or JavaSE-11). To determine the JVM version running on the target device, log in to its administrative console and enter the command
java \u2013version
Finally, uncheck the Generate an activator, a Java class that controls the plug-in\u2019s life cycle option button. For the purposes of this example, a single class will be used. An Activator class will not be created; instead, OSGi Declarative Services will be used to start and stop the bundle.
Click Finish.
If the Open Associated Perspective pop-up window (shown below) appears for adding Plug-ins and Error Log views, select Yes or No depending on your development requirements.
You should see the new project in the My Projects working set in the Package Explorer (or Project Explorer). Also, you will see the MANIFEST.MF was automatically opened in the Manifest Editor. An OSGi bundle is a regular Java .jar file that contains Java code and resources and a custom Manifest and an Activator.
"},{"location":"java-application-development/hello-world-application/#add-dependencies-to-manifest","title":"Add Dependencies to Manifest","text":"First, you will use the Manifest Editor in Eclipse to add some dependencies. Click the Dependencies tab at the bottom of the editor screen and then click the Automated Management of Dependencies heading to expand it.
Under Automated Management of Dependencies, click Add. In the Select a Plug-in field, enter org.eclipse.osgi.services. Select the plug-in name and click OK.
Note that this operation is very much like adding standalone jars to the buildpath by including the \u2018-cp\u2019 argument to javac. However, in this case you are telling Eclipse where to find these dependencies the \u201cOSGi way\u201d, so it is aware of them at compile time. Click Add again and use the same procedure to add the following dependency:
You should now see the list of dependencies. Save changes to the Manifest.
"},{"location":"java-application-development/hello-world-application/#create-java-class","title":"Create Java Class","text":"Now you are ready to start writing a simple Java class. Right-click the org.eclipse.kura.example.hello_osgi project. Select New | Class. The New Java Class window appears as shown below. Set the Source folder to org.eclipse.kura.example.hello_osgi/src. Set the Package field to org.eclipse.kura.example.hello_osgi, set the Name field to HelloOsgi, and then click Finish.
Write the following code for the new class. You can copy and paste the code provided below into your newly created Java class file.
package org.eclipse.kura.example.hello_osgi;\n\npublic class HelloOsgi {\n\n private static final Logger s_logger = LoggerFactory.getLogger(HelloOsgi.class);\n\n private static final String APP_ID = \"org.eclipse.kura.example.hello_osgi\";\n\n protected void activate(ComponentContext componentContext) {\n\n s_logger.info(\"Bundle \" + APP_ID + \" has started!\");\n\n s_logger.debug(APP_ID + \": This is a debug message.\");\n\n }\n\n protected void deactivate(ComponentContext componentContext) {\n\n s_logger.info(\"Bundle \" + APP_ID + \" has stopped!\");\n\n }\n\n}\n
The activate() method is the entry point when the bundle in started. The deactivate() method is the entry point when the bundle is stopped.
Notice the use of the private LoggerFactory.getLogger() method. If the LoggerFactory method is present (running) in the OSGi framework and your hello_osgi bundle is started, your activate method is called, and you can simply access the service by calling the getLogger() method.
One convenient feature of Eclipse, auto-completion, is worth mentioning here. If you type \u2018s_logger.\u2019 (instance name of the \u201cLoggerFactory.getLogger\u201d method) and stop after the period, it will show you a list of methods implemented in that class. The examples above show two different methods used for logging messages. Logger methods include: \u201cerror\u201d, \u201cwarn\u201d, \u201cinfo\u201d, \u201cdebug\u201d, and \u201ctrace\u201d, which represent increasingly lower (more detailed) levels of log information. Logger levels should generally be used to represent the following conditions:
ERROR - A serious problem has occurred that requires attention from the system administrator.
WARNING - An action occurred or a condition was discovered that should be reviewed and may require action before an error occurs. It may also be used for transient issues.
INFO - A report of a normal action or event. This could be a user operation, such as \"login completed\", or an automatic operation, such as a log file rotation.
DEBUG - A debug message used for troubleshooting or performance monitoring. It typically contains detailed event data including things an application developer would need to know.
TRACE - A fairly detailed output of diagnostic logging, such as actual bytes of a particular message being examined.
At this point, there will be errors in your code because of unresolved imports.
Select the menu Source | Organize Imports to resolve these errors. Because you added the \u201corg.slf4j\u201d to your dependency list, you will be prompted to choose one of two potential sources for importing the \u201cLogger\u201d class. Select org.slf4j.Logger and click Finish.
Now the errors in the class should have been resolved. Save the HelloOsgi class.
The complete set of code (with import statements) is shown below.
package org.eclipse.kura.example.hello_osgi;\n\nimport org.osgi.service.component.ComponentContext;\n\nimport org.slf4j.Logger;\n\nimport org.slf4j.LoggerFactory;\n\npublic class HelloOsgi {\n\n private static final Logger s_logger = LoggerFactory.getLogger(HelloOsgi.class);\n\n private static final String APP_ID = \"org.eclipse.kura.example.hello_osgi\";\n\n protected void activate(ComponentContext componentContext) {\n\n s_logger.info(\"Bundle \" + APP_ID + \" has started!\");\n\n s_logger.debug(APP_ID + \": This is a debug message.\");\n\n }\n\n protected void deactivate(ComponentContext componentContext) {\n\n s_logger.info(\"Bundle \" + APP_ID + \" has stopped!\");\n\n }\n\n}\n
For more information on using the Simple Logging Facade for Java (slf4j), see the Logger API.
Switch back to the Manifest Editor. Under Automated Management of Dependencies, ensure the Import-Package option button is selected. Click the add dependencies link to automatically add packages to the dependencies list based on the \u201cimport\u201d statements in your example code. Save changes to the Manifest again.
"},{"location":"java-application-development/hello-world-application/#create-component-class","title":"Create Component Class","text":"Right-click the example project and select New | Other. From the wizard, select Plug-in Development | Component Definition and click Next.
Warning
This option is available only if the Plug-in Development Environment (PDE) is installed in Eclipse (plugins can be installed into Eclipse IDE by searching the name in the Eclipse Marketplace under the Help menu).
In the Class field of the New Component Definition window shown below, click Browse.
Enter the name of your newly created class in the Select entries field. In this case, type the word \u201chello\u201d, and you will see a list of matching items. Select the HelloOsgi class and click OK.
In the Enter or select the parent folder field of the New Component Definition window, add \"/OSGI-INF\" to the existing entry (e.g., org.eclipse.kura.example.hello_osgi/OSGI-INF). Then click Finish.
After the Component class has been created, it will open in the Workspace. In the Overview tab, the Name and Class point to our Java class. Set the Activate field to activate and set the Deactivate field to deactivate. Doing so tells the component where these OSGi activation methods are located. Then save the Component class definition file.
"},{"location":"java-application-development/hello-world-application/#deploying-the-plug-in","title":"Deploying the Plug-in","text":"The next few sections describe how to create a stand-alone JAR file as a deployable OSGI plug-in and how to create an installable Deployment Package.
An OSGi bundle is a Java archive file containing Java code, resources, and a Manifest.
A Deployment Package is a set of resources grouped into a single package file that may be deployed in the OSGi framework through the Deployment Admin service and may contain one or more bundles, configuration objects, etc.
"},{"location":"java-application-development/hello-world-application/#export-the-osgi-bundle","title":"Export the OSGi Bundle","text":"Your bundle can be built as a stand-alone OSGi plug-in.
To do so, right-click the project and select the Export menu. This is equivalent to running javac on your project. From the wizard, select Plug-in Development | Deployable plug-ins and fragments and click Next.
Under Available Plug-ins and Fragments of the Export window, ensure the newly created plug-in is selected. Under Destination, select the Directory option button and use the Browse button to select an appropriate place to save the JAR file on the local file system.
NOTE: During the deployment process that is described in the following section, you will need to remember the location where this JAR file is saved.
Click Finish.
This will create a JAR file in the selected directory (e.g., /home/joe/myPlugins/plugins/org.eclipse.kura.example.hello_osgi_1.0.0.jar).
"},{"location":"java-application-development/hello-world-application/#create-a-deployment-package","title":"Create a Deployment Package","text":"Rather than creating a stand-alone plug-in, you can also create a Deployment Package that contains multiple bundles, configuration elements, etc. that can be deployed into an OSGi framework. In this example, you will simply create a Deployment Package containing the \u201chello_osgi\u201d bundle. This step requires mToolkit to be installed. (See Kura Setup for instructions on setting up the Eclipse development environment.)
Right-click the project and select New | Folder. Select the org.eclipse.kura.example.hello_osgi project and enter a folder named \u201cresources\u201d.
Then repeat this step to create a folder named \u201cdp\u201d under the resources folder. The resources/dp folder will be used to store the Deployment Package.
Select File | New | Other. Select OSGi | Deployment Package Definition and click Next.
Ensure that the Target folder field of the New dpp file window is set to the /[project_name]/resources/dp folder. In the File name field, enter the name for the new Deployment Package file to create, such as \u201chello_osgi\u201d. A version number can also be entered in the Version field. Then click Finish.
Under the resources/dp folder in your project, verify that the [filename].dpp file was created. This is a Deployment Package Project that provides information needed to create the Deployment Package, such as its output directory, ant build file, etc.
Select the Bundles tab and then click New. In the Bundle Path column, select the browse icon. Browse to the bundle\u2019s JAR file created earlier. Select the file and click Open. Doing so should populate the remaining columns as needed.
Save changes to the deployment package file.
In the resources/dp folder, right-click the .dpp file. Select Quick Build. A new [filename].dp file will be created in the same directory. This is the final Deployment Package that can be installed on a remote target system.
In conclusion, you were able to create a new bundle from scratch, write the Java code and Activator, modify the Manifest, and build the plug-in and/or Deployment Package that can be used in a Kura environment.
The next steps will be to test your code in an Emulation mode and/or to deploy your code to a target system running Kura. See Testing and Deploying Bundles to continue with those steps.
"},{"location":"java-application-development/how-to-manage-network-settings/","title":"How to manage Network Settings","text":"This section provides an example of how to create a Kura bundle that can be used to configure the network interfaces of your device. In this example, you will learn how to perform the following functions:
Create a plugin that configures the network interfaces
Connect to a wireless access point
Create a wireless access point
As written, the example code configures the device with a static Wi-Fi configuration. Typically, the device settings would be defined through the Kura Gateway Administration Console instead of through Java code.
A more practical application of this example is for IP network interfaces that need to be dynamically modified based on some external trigger or condition, such as geo-fencing. The Kura framework allows the device to be programmatically changed via its APIs based on application-specific logic.
"},{"location":"java-application-development/how-to-manage-network-settings/#prerequisites","title":"Prerequisites","text":"Setting up the Eclipse Kura Development Environment
"},{"location":"java-application-development/how-to-manage-network-settings/#network-configuration-with-kura","title":"Network Configuration with Kura","text":""},{"location":"java-application-development/how-to-manage-network-settings/#hardware-setup","title":"Hardware Setup","text":"This example requires an embedded device running Kura with at least one Ethernet port and Wi-Fi support.
Additionally, the Connect to an Access Point section requires a wireless access point and the following information about the access point:
SSID (Network Name)
Security Type (WEP, WPA, or WPA2), if any
Password/Passphrase, if any
Lastly, the Create an Access Point section requires:
A wireless device, such as a laptop, to test the access point.
Optionally, you may connect the Kura device\u2019s Ethernet port to another network and use Kura as a gateway to that network.
In order to determine your network interfaces, run one of the following commands at a terminal on the embedded gateway:
ifconfig -a
or ip link show
Typical network interfaces will appear as follows:
lo - loopback interface
eth0 - first Ethernet network interface
wlan0 - first wireless network interface
ppp0 - first point-to-point protocol network interface, which could be a dial-up modem, PPTP VPN connection, cellular modem, etc.
Make note of your wireless interface. For this tutorial, we will assume the wireless interface name is \u2018wlan0\u2019.
"},{"location":"java-application-development/how-to-manage-network-settings/#kura-networking-api","title":"Kura Networking API","text":"The networking API consists of two basic services: org.eclipse.kura.net.NetworkService
and org.eclipse.kura.net.NetworkAdminService
.
The NetworkService is used to get the current state of the network. For example, the getNetworkInterfaces() method will return a List of NetInterface objects (such as EthernetInterface or WifiInterface) for each interface. This provides a detailed representation of the current state of that interface, such as its type, whether it is currently up, and its current address, which is returned by the getNetInterfaceAddresses() method as a List of NetInterfaceAddress objects. The NetworkService can also be used to get a list of all the network interface names available on the system, or a list of all the Wi-Fi access points that are currently detected by the system.
The NetworkAdminService is used to get and set the configuration for each interface. Similar to the NetworkService, it has a getNetworkInterfaceConfigs() that returns a List of NetInterfaceConfig objects (such as EthernetInterfaceConfig and WifiInterfaceConfig) for each interface. These have the same methods as a NetInterface object but represent the current configuration for that interface. For a NetInterfaceConfig object, the getNetInterfaceAddress() method will return a List of NetInterfaceAddressConfig objects. These NetInterfaceAddressConfig instances, in turn, contain a List of NetConfig objects that define the configuration for that interface.
There are many types of NetConfig objects, including:
NetConfigIP4 - contains the IPv4 address configuration
WifiConfig - contains the Wi-Fi configuration. Note that a WifiInterfaceAddressConfig may contain multiple WifiConfigs, since a configuration might exist for one or more Wi-Fi modes. The currently active WifiConfig is the one with a WifiMode that matches the WifiInterfaceAddressConfig WifiMode.
DhcpServerConfigIP4 - contains the IPv4-based DHCP server configuration
DnsServerConfigIP4 - contains the IPv4-based DNS server configuration
FirewallNatConfig - contains the firewall NAT configuration
These NetConfigs can also be used to configure an interface by providing them as a list to the updateEthernetInterfaceConfig()
, updateWifiInterfaceConfig()
, or updateModemInterfaceConfig()
methods in the NetworkAdminService.
In this section, you will develop a Kura network configuration bundle that sets up the Wi-Fi interface as a client to a wireless access point.
"},{"location":"java-application-development/how-to-manage-network-settings/#implement-the-bundle","title":"Implement the Bundle","text":"To implement the network configuration bundle, perform the following steps:
Note
For more detailed information about bundle development (i.e., the plug-in project, classes, and MANIFEST file configuration), please refer to the Hello World Application
Create a Plug-in Project named org.eclipse.kura.example.network
; set the an OSGi framework option to standard; uncheck the Generate an activator option; and set the Execution Environment variable to match the JVM on your target device.
Include the following bundles in the MANIFEST.MF:
org.slf4j
Create a class named NetworkConfigExample in the org.eclipse.kura.example.network project.
Create an OSGI-INF folder in the org.eclipse.kura.example.network project. Add a Component Class with the parent folder org.eclipse.kura.example.network/OSGI-INF, Component Name org.eclipse.kura.example.network, and Class org.eclipse.kura.example.network.NetworkConfigExample.
Select the Services tab in the component.xml file. Under Referenced Services, add org.eclipse.kura.net.NetworkAdminService. Edit the properties of this service, and configure the Bind property to setNetworkAdminService and Unbind to unsetNetworkAdminService as shown in the following screen capture. These settings are required because of the dependency on NetworkAdminService.
The following source code will also need to be implemented:
META-INF/MANIFEST.MF - OSGI manifest that describes the bundle and its dependencies.
OSGI-INF/component.xml - declarative services definition describing what services are exposed by and consumed by this bundle.
org.eclipse.kura.example.network.NetworkConfigExample.java - main implementation class.
The META-INF/MANIFEST.MF file should look as follows when complete:
Warning
Whitespace is significant in this file; make sure yours matches this file exactly.
Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Network\nBundle-SymbolicName: org.eclipse.kura.example.network\nBundle-Version: 1.0.0.qualifier\nBundle-Vendor: ECLIPSE\nBundle-RequiredExecutionEnvironment: JavaSE-1.7\nImport-Package: org.eclipse.kura,\n org.eclipse.kura.net,\n org.eclipse.kura.net.dhcp,\n org.eclipse.kura.net.firewall,\n org.eclipse.kura.net.wifi,\n org.osgi.service.component;version=\"1.2.0\",\n org.slf4j;version=\"1.6.4\"\nService-Component: OSGI-INF/component.xml\n
"},{"location":"java-application-development/how-to-manage-network-settings/#osgi-infcomponentxml-file","title":"OSGI-INF/component.xml File","text":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\"\n name=\"org.eclipse.kura.example.network.NetworkConfigExample\"\n activate=\"activate\"\n deactivate=\"deactivate\"\n enabled=\"true\"\n immediate=\"true\"\n configuration-policy=\"require\"\n modified=\"updated\">\n <implementation class=\"org.eclipse.kura.example.network.NetworkConfigExample\"/>\n <service>\n <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n </service>\n <reference name=\"NetworkAdminService\"\n interface=\"org.eclipse.kura.net.NetworkAdminService\"\n policy=\"static\"\n cardinality=\"1..1\"\n bind=\"setNetworkAdminService\"\n unbind=\"unsetNetworkAdminService\"/>\n <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.example.network.NetworkConfigExample\"/>\n</scr:component>\n
"},{"location":"java-application-development/how-to-manage-network-settings/#orgeclipsekuraexamplenetworknetworkconfigexamplejava","title":"org.eclipse.kura.example.network.NetworkConfigExample.java","text":"package org.eclipse.kura.example.network;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.net.IP4Address;\nimport org.eclipse.kura.net.IPAddress;\nimport org.eclipse.kura.net.NetConfig;\nimport org.eclipse.kura.net.NetConfigIP4;\nimport org.eclipse.kura.net.NetInterfaceStatus;\nimport org.eclipse.kura.net.NetworkAdminService;\nimport org.eclipse.kura.net.dhcp.DhcpServerConfigIP4;\nimport org.eclipse.kura.net.firewall.FirewallNatConfig;\nimport org.eclipse.kura.net.wifi.WifiCiphers;\nimport org.eclipse.kura.net.wifi.WifiConfig;\nimport org.eclipse.kura.net.wifi.WifiMode;\nimport org.eclipse.kura.net.wifi.WifiRadioMode;\nimport org.eclipse.kura.net.wifi.WifiSecurity;\n\npublic class NetworkConfigExample {\n\n private static final Logger s_logger = LoggerFactory.getLogger(NetworkConfigExample.class);\n\n private NetworkAdminService m_netAdminService;\n\n // ----------------------------------------------------------------\n //\n // Dependencies\n //\n // ----------------------------------------------------------------\n\n public void setNetworkAdminService(NetworkAdminService netAdminService) {\n this.m_netAdminService = netAdminService;\n }\n\n public void unsetNetworkAdminService(NetworkAdminService netAdminService) {\n this.m_netAdminService = null;\n }\n\n\n // ----------------------------------------------------------------\n //\n // Activation APIs\n //\n // ----------------------------------------------------------------\n\n protected void activate(ComponentContext componentContext) {\n s_logger.info(\"Activating NetworkConfigExample...\");\n\n connectToWirelessAccessPoint();\n// createWirelessAccessPoint();\n\n s_logger.info(\"Activating NetworkConfigExample... Done.\");\n }\n\n protected void deactivate(ComponentContext componentContext) {\n s_logger.info(\"Deactivating NetworkConfigExample...\");\n\n s_logger.info(\"Deactivating NetworkConfigExample... Done.\");\n }\n\n\n // ----------------------------------------------------------------\n //\n // Private Methods\n //\n // ----------------------------------------------------------------\n\n /**\n * Connect to a wireless access point using the hard-coded parameters below\n */\n private void connectToWirelessAccessPoint() {\n String interfaceName = \"wlan0\";\n\n // Create a NetConfigIP4 - configure as a WAN (gateway) interface, and a DHCP client\n NetInterfaceStatus netInterfaceStatus = NetInterfaceStatus.netIPv4StatusEnabledWAN;\n boolean dhcpClient = true;\n boolean autoConnect = true;\n NetConfigIP4 netConfigIP4 = new NetConfigIP4(netInterfaceStatus, autoConnect, dhcpClient);\n\n // Create a WifiConfig managed mode client\n String driver = \"nl80211\";\n String ssid = \"access_point_ssid\";\n String password = \"password\";\n WifiSecurity security = WifiSecurity.SECURITY_WPA2;\n WifiCiphers ciphers = WifiCiphers.CCMP_TKIP;\n int[] channels = {1,2,3,4,5,6,7,8,9,10,11};\n\n WifiConfig wifiConfig = new WifiConfig();\n wifiConfig.setMode(WifiMode.INFRA);\n wifiConfig.setDriver(driver);\n wifiConfig.setSSID(ssid);\n wifiConfig.setPasskey(password);\n wifiConfig.setSecurity(security);\n wifiConfig.setChannels(channels);\n wifiConfig.setGroupCiphers(ciphers);\n wifiConfig.setPairwiseCiphers(ciphers);\n\n // Create a NetConfig List\n List<NetConfig> netConfigs = new ArrayList<NetConfig>();\n netConfigs.add(netConfigIP4);\n netConfigs.add(wifiConfig);\n\n // Configure the interface\n try{\n s_logger.info(\"Reconfiguring \" + interfaceName + \" to connect to \" + ssid);\n m_netAdminService.disableInterface(interfaceName);\n m_netAdminService.updateWifiInterfaceConfig(interfaceName, autoConnect, null, netConfigs);\n\n s_logger.info(\"Enable \" + interfaceName);\n m_netAdminService.enableInterface(interfaceName, dhcpClient);\n } catch(KuraException e) {\n s_logger.error(\"Error connecting to wireless access point\", e);\n }\n }\n\n /**\n * Create a wireless access point\n */\n private void createWirelessAccessPoint() {\n try{\n String interfaceName = \"wlan0\";\n\n // Create a NetConfigIP4 - configure as a LAN interface with a manual IP address\n NetInterfaceStatus netInterfaceStatus = NetInterfaceStatus.netIPv4StatusEnabledLAN;\n boolean dhcpClient = false;\n boolean autoConnect = true;\n IP4Address ipAddress = (IP4Address) IPAddress.parseHostAddress(\"172.16.10.1\");\n IP4Address subnetMask = (IP4Address) IPAddress.parseHostAddress(\"255.255.255.0\");\n\n NetConfigIP4 netConfigIP4 = new NetConfigIP4(netInterfaceStatus, autoConnect);\n netConfigIP4.setAddress(ipAddress);\n netConfigIP4.setSubnetMask(subnetMask);\n\n // Create a WifiConfig access point\n String driver = \"nl80211\";\n String ssid = \"NetworkConfigExample\";\n String password = \"password\";\n WifiSecurity security = WifiSecurity.SECURITY_WPA2;\n WifiCiphers ciphers = WifiCiphers.CCMP_TKIP;\n int[] channels = {1};\n WifiRadioMode radioMode = WifiRadioMode.RADIO_MODE_80211g;\n String hwMode = \"g\";\n\n WifiConfig wifiConfig = new WifiConfig();\n wifiConfig.setMode(WifiMode.MASTER);\n wifiConfig.setDriver(driver);\n wifiConfig.setSSID(ssid);\n wifiConfig.setPasskey(password);\n wifiConfig.setSecurity(security);\n wifiConfig.setChannels(channels);\n wifiConfig.setGroupCiphers(ciphers);\n wifiConfig.setPairwiseCiphers(ciphers);\n wifiConfig.setRadioMode(radioMode);\n wifiConfig.setHardwareMode(hwMode);\n\n\n // Create a DhcpServerConfig to enable DHCP server functionality\n int defaultLeaseTime = 7200;\n int maximumLeaseTime = 7200;\n IP4Address routerAddress = ipAddress;\n IP4Address rangeStart = (IP4Address) IPAddress.parseHostAddress(\"172.16.10.100\");\n IP4Address rangeEnd = (IP4Address) IPAddress.parseHostAddress(\"172.16.10.200\");\n IP4Address dhcpSubnetMask = (IP4Address) IPAddress.parseHostAddress(\"255.255.255.0\");\n IP4Address subnet = (IP4Address) IPAddress.parseHostAddress(\"172.16.10.0\");\n short prefix = 24;\n boolean passDns = true;\n\n List<IP4Address> dnsServers = new ArrayList<IP4Address>();\n dnsServers.add(ipAddress); // Use our IP as the DNS server\n\n DhcpServerConfigIP4 dhcpServerConfigIP4 = new DhcpServerConfigIP4(\n interfaceName, true, subnet, routerAddress, dhcpSubnetMask, defaultLeaseTime,\n maximumLeaseTime, prefix, rangeStart, rangeEnd, passDns, dnsServers);\n\n // Create a FirewallNatConfig to enable NAT (network address translation)\n // note that the destination interface is determined dynamically\n FirewallNatConfig natConfig = new FirewallNatConfig(interfaceName, \"tbd\", true);\n\n\n // Create a NetConfig List\n List<NetConfig> netConfigs = new ArrayList<NetConfig>();\n netConfigs.add(netConfigIP4);\n netConfigs.add(wifiConfig);\n netConfigs.add(dhcpServerConfigIP4);\n netConfigs.add(natConfig);\n\n // Configure the interface\n s_logger.info(\"Reconfiguring \" + interfaceName + \" as an access point with SSID: \" + ssid);\n m_netAdminService.disableInterface(interfaceName);\n m_netAdminService.updateWifiInterfaceConfig(interfaceName, autoConnect, null, netConfigs);\n\n s_logger.info(\"Enable \" + interfaceName);\n m_netAdminService.enableInterface(interfaceName, dhcpClient);\n } catch(Exception e) {\n s_logger.error(\"Error configuring as an access point\", e);\n }\n }\n}\n
Modify the parameters in the connectToWirelessAccessPoint() method with the specific values for the access point you want to connect to, including the variables for SSID, password, and security settings:
String ssid = \"access_point_ssid\";
String password = \"password\";
WifiSecurity security = WifiSecurity.SECURITY_WPA2;
At this point, the bundle implementation is complete. Make sure to save all files before proceeding.
Export the OSGi bundle as a stand-alone plug-in, following the instructions in Hello World Using the Kura Logger.
"},{"location":"java-application-development/how-to-manage-network-settings/#deploy-the-bundle","title":"Deploy the Bundle","text":"In order to proceed, you need to know the IP address of your embedded gateway that is running Kura. Follow the mToolkit instructions for installing a single bundle to the remote target device located here. Once the bundle has finished deploying, it will set the device\u2019s network configuration and attempt to connect to a Wi-Fi access point using the configured parameters in the connectToWirelessAccessPoint() method.
"},{"location":"java-application-development/how-to-manage-network-settings/#test-the-connection-to-the-access-point","title":"Test the Connection to the Access Point","text":"To verify that the interface (wlan0) has acquired an IP address, run the ifconfig command at a terminal on the embedded gateway.
To show the current connection status to the access point, run the following commands:
wpa_cli -i wlan0 status\niw dev wlan0 link\niw dev wlan0 station dump\n
"},{"location":"java-application-development/how-to-manage-network-settings/#create-an-access-point","title":"Create an Access Point","text":"This example code can be modified slightly to make the gateway function as an access point instead of connecting to an access point.
To do this, modify the activate() method in the NetworkConfigExample.java file to comment out connectToWirelessAccessPoint()
and uncomment createWirelessAccessPoint()
.
protected void activate(ComponentContext componentContext) {\n s_logger.info(\"Activating NetworkConfigExample...\");\n\n// connectToWirelessAccessPoint();\n createWirelessAccessPoint();\n\n s_logger.info(\"Activating NetworkConfigExample... Done.\");\n}\n
Modify the access point configuration variables under createWirelessAccessPoint() for your needs, if necessary, such as the variables:
IP4Address ipAddress = (IP4Address) IPAddress.parseHostAddress(\"172.16.10.1\");\nIP4Address subnetMask = (IP4Address) IPAddress.parseHostAddress(\"255.255.255.0\");\n\n// Create a WifiConfig access point\nString driver = \"nl80211\";\nString ssid = \"NetworkConfigExample\";\nString password = \"password\";\n
Export the bundle again as a stand-alone OSGi plug-in and redeploy it to the target device. It should now reconfigure itself to create an access point with an active DHCP server, DNS proxy forwarding, and NAT enabled.
"},{"location":"java-application-development/how-to-manage-network-settings/#test-the-access-point","title":"Test the Access Point","text":"To verify that the interface (wlan0) has a fixed IP address, run the ifconfig command at a terminal on the embedded gateway.
To view information on the Wi-Fi access point, including interface name, wireless channel, and MAC address, enter:
iw dev wlan0 info
To monitor connect and disconnect events from the access point, enter:
iw event \u2013f
Use another wireless client, such as a laptop, to verify that you can connect to the access point, that it receives an IP address, and that it can ping the network. When the client connects to the access point, the console should show a new station connection event.
To view station statistic information, including signal strength and bitrate, enter:
iw dev wlan0 station dump
Optionally, if the gateway has another interface configured for WAN with connection to the Internet, then the wireless client should be able to reach the Internet using this access point as its gateway. The setup for the other interface (not covered in this example) would need to be configured in the device using the Kura Gateway Administration Console.
"},{"location":"java-application-development/how-to-serial-ports/","title":"How to Use Serial Ports","text":""},{"location":"java-application-development/how-to-serial-ports/#overview","title":"Overview","text":"This section provides an example of how to create a Kura bundle that will communicate with a serial device. In this example, you will communicate with a simple terminal emulator to demonstrate both transmitting and receiving data. You will learn how to perform the following functions:
Create a plugin that communicates to serial devices
Export the bundle
Install the bundle on the remote device
Test the communication with minicom where, minicom is acting as an attached serial device such as an NFC reader, GPS device, or some other ASCII-based communication device
Setting up Kura Development Environment
Hello World Using the Kura Logger
Hardware
Use an embedded device running Kura with two available serial ports. (If the device does not have a serial port, USB to serial adapters can be used.)
Ensure minicom is installed on the embedded device.
This section of the tutorial covers setting up the hardware, determining serial port device nodes, implementing the basic serial communication bundle, deploying the bundle, and validating its functionality. After completing this section, you should be able to communicate with any ASCII-based serial device attached to a Kura-enabled embedded gateway. In this example, we are using ASCII for clarity, but these same techniques can be used to communicate with serial devices that communicate using binary protocols.
"},{"location":"java-application-development/how-to-serial-ports/#hardware-setup","title":"Hardware Setup","text":"Your setup requirements will depend on your hardware platform. At a minimum, you will need two serial ports with a null modem serial, crossover cable connecting them.
If your platform has integrated serial ports, you only need to connect them using a null modem serial cable.
If you do not have integrated serial ports on your platform, you will need to purchase USB-to-Serial adapters. It is recommended to use a USB-to-Serial adapter with either the PL2303 or FTDI chipset, but others may work depending on your hardware platform and underlying Linux support. Once you have attached these adapters to your device, you can attach the null modem serial cable between the two ports.
This step is hardware specific. If your hardware device has integrated serial ports, contact your hardware device manufacturer or review the documentation to find out how the ports are named in the operating system. The device identifiers should be similar to the following:
/dev/ttyS*xx*\n/dev/ttyUSB*xx*\n/dev/ttyACM*xx*\n
If you are using USB-to-Serial adapters, Linux usually allocates the associated device nodes dynamically at the time of insertion. In order to determine what they are, run the following command at a terminal on the embedded gateway:
tail -f /var/log/syslog\n
Warning
Depending on your specific Linux implementation, other possible log files may be: /var/log/kern.log, /var/log/kernel, or /var/log/dmesg.
With the above command running, insert your USB-to-Serial adapter. You should see output similar to the following:
root@localhost:/root> tail -f /var/log/syslog\nAug 15 18:43:47 localhost kernel: usb 3-2: new full speed USB device using uhci_hcd and address 3\nAug 15 18:43:47 localhost kernel: pl2303 3-2:1.0: pl2303 converter detected\nAug 15 18:43:47 localhost kernel: usb 3-2: pl2303 converter now attached to ttyUSB10\n
In this example, our device is a PL2303-compatible device and is allocated a device node of \u201c/dev/ttyUSB10\u201d. While your results may differ, the key is to identify the \u201ctty\u201d device that was allocated. For the rest of this tutorial, this device will be referred to as [device_node_1], which in this example is /dev/ttyUSB10. During development, it is also important to keep in mind that these values are dynamic; therefore, from one boot to the next and one insertion to the next, these values may change. To stop \u2018tail\u2019 from running in your console, escape with \u2018 c\u2019.
If you are using two USB-to-Serial adapters, repeat the above procedure for the second serial port. The resulting device node will be referred to as [device_node_2].
"},{"location":"java-application-development/how-to-serial-ports/#implement-the-bundle","title":"Implement the Bundle","text":"Now that you have two serial ports connected to each other, you are ready to implement the code. You will use the same general method that is described in section Hello World Application with the following exceptions:
The following files need to be implemented:
META-INF/MANIFEST.MF \u2013 OSGI manifest that describes the bundle and its dependencies
OSGI-INF/component.xml \u2013 declarative services definition that describe what services are exposed and consumed by this bundle
OSGI-INF/metatype/org.eclipse.kura.example.serial.SerialExample.xml \u2013 configuration description of the bundle and its parameters, types, and defaults
org.eclipse.kura.example.serial.SerialExample.java \u2013 main implementation class
The META-INF/MANIFEST.MF file should appear as shown below when complete:
NOTE: Whitespace is significant in this file. Make sure yours matches this file exactly with the exception that RequiredExecutionEnvironment may be JavaSE-1.6 or JavaSE-1.7, depending on the Java installation of your device.
Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Serial\nBundle-SymbolicName: org.eclipse.kura.example.serial\nBundle-Version: 1.0.0.qualifier\nBundle-RequiredExecutionEnvironment: JavaSE-1.7\nService-Component: OSGI-INF/component.xml\nBundle-ActivationPolicy: lazy\nImport-Package: javax.comm;version=\"1.2.0\",\n javax.microedition.io;resolution:=optional,\n org.eclipse.kura.cloud;version=\"0.2.0\",\n org.eclipse.kura.comm;version=\"0.2.0\",\n org.eclipse.kura.configuration;version=\"0.2.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.osgi.service.io;version=\"1.0.0\",\n org.slf4j;version=\"1.6.4\"\nBundle-ClassPath: .\n
In addition, the build.properties file should have org.eclipse.equinox.io listed as an additional bundle similar to below:
additional.bundles = org.eclipse.equinox.io\n
"},{"location":"java-application-development/how-to-serial-ports/#osgi-infcomponentxml-file","title":"OSGI-INF/component.xml File","text":"Warning
Starting from Kura 3.0, the configuration service will only track \"relevant services\" that, in their component description files, will provide the ConfigurableComponent or SelfConfigurableComponent interface. The old behavior can be restored by setting the \"org.eclipse.kura.core.configuration.legacyServiceTracking\" property to true.
If Kura 2.1.0 or older versions are used or the org.eclipse.kura.core.configuration.legacyServiceTracking
system property is set to true, the OSGI-INF/component.xml should appear as shown below when complete:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\"\n name=\"org.eclipse.kura.example.serial.SerialExample\" activate=\"activate\"\n deactivate=\"deactivate\" modified=\"updated\" enabled=\"true\" immediate=\"true\"\n configuration-policy=\"require\">\n\n <implementation class=\"org.eclipse.kura.example.serial.SerialExample\"/>\n <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.example.serial.SerialExample\"/>\n\n <service>\n <provide interface=\"org.eclipse.kura.example.serial.SerialExample\"/>\n </service>\n <reference bind=\"setConnectionFactory\" cardinality=\"1..1\"\n interface=\"org.osgi.service.io.ConnectionFactory\" name=\"ConnectionFactory\"\n policy=\"static\" unbind=\"unsetConnectionFactory\" />\n</scr:component>\n
If Kura 3.0 or newer versions are used and the org.eclipse.kura.core.configuration.legacyServiceTracking
system property is set to false or not set, the OSGI-INF/component.xml should appear as shown below when complete:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\"\n name=\"org.eclipse.kura.example.serial.SerialExample\" activate=\"activate\"\n deactivate=\"deactivate\" modified=\"updated\" enabled=\"true\" immediate=\"true\"\n configuration-policy=\"require\">\n\n <implementation class=\"org.eclipse.kura.example.serial.SerialExample\"/>\n <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.example.serial.SerialExample\"/>\n\n <service>\n <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n </service>\n <reference bind=\"setConnectionFactory\" cardinality=\"1..1\"\n interface=\"org.osgi.service.io.ConnectionFactory\" name=\"ConnectionFactory\"\n policy=\"static\" unbind=\"unsetConnectionFactory\" />\n</scr:component>\n
"},{"location":"java-application-development/how-to-serial-ports/#osgi-infmetatypeorgeclipsekuraexampleserialserialexamplexml-file","title":"OSGI-INF/metatype/org.eclipse.kura.example.serial.SerialExample.xml File","text":"The OSGI-INF/metatype/org.eclipse.kura.example.serial.SerialExample.xml file should appear as shown below when complete:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n <OCD id=\"org.eclipse.kura.example.serial.SerialExample\"\n name=\"SerialExample\"\n description=\"Example of a Configuring KURA Application echoing data read from the serial port.\">\n\n <Icon resource=\"http://sphotos-a.xx.fbcdn.net/hphotos-ash4/p480x480/408247_10151040905591065_1989684710_n.jpg\" size=\"32\"/>\n\n <AD id=\"serial.device\"\n name=\"serial.device\"\n type=\"String\"\n cardinality=\"0\"\n required=\"false\"\n description=\"Name of the serial device (e.g. /dev/ttyS0, /dev/ttyACM0, /dev/ttyUSB0).\"/>\n\n <AD id=\"serial.baudrate\"\n name=\"serial.baudrate\"\n type=\"String\"\n cardinality=\"0\"\n required=\"true\"\n default=\"9600\"\n description=\"Baudrate.\">\n <Option label=\"9600\" value=\"9600\"/>\n <Option label=\"19200\" value=\"19200\"/>\n <Option label=\"38400\" value=\"38400\"/>\n <Option label=\"57600\" value=\"57600\"/>\n <Option label=\"115200\" value=\"115200\"/>\n </AD>\n\n <AD id=\"serial.data-bits\"\n name=\"serial.data-bits\"\n type=\"String\"\n cardinality=\"0\"\n required=\"true\"\n default=\"8\"\n description=\"Data bits.\">\n <Option label=\"7\" value=\"7\"/>\n <Option label=\"8\" value=\"8\"/>\n </AD>\n\n <AD id=\"serial.parity\"\n name=\"serial.parity\"\n type=\"String\"\n cardinality=\"0\"\n required=\"true\"\n default=\"none\"\n description=\"Parity.\">\n <Option label=\"none\" value=\"none\"/>\n <Option label=\"even\" value=\"even\"/>\n <Option label=\"odd\" value=\"odd\"/>\n </AD>\n\n <AD id=\"serial.stop-bits\"\n name=\"serial.stop-bits\"\n type=\"String\"\n cardinality=\"0\"\n required=\"true\"\n default=\"1\"\n description=\"Stop bits.\">\n <Option label=\"1\" value=\"1\"/>\n <Option label=\"2\" value=\"2\"/>\n </AD>\n\n </OCD>\n <Designate pid=\"org.eclipse.kura.example.serial.SerialExample\">\n <Object ocdref=\"org.eclipse.kura.example.serial.SerialExample\"/>\n </Designate>\n</MetaData>\n
"},{"location":"java-application-development/how-to-serial-ports/#orgeclipsekuraexampleserialserialexamplejava-file","title":"org.eclipse.kura.example.serial.SerialExample.java File","text":"The org.eclipse.kura.example.serial.SerialExample.java file should appear as shown below when complete:
package org.eclipse.kura.example.serial;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.ScheduledThreadPoolExecutor;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.io.ConnectionFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class SerialExample implements ConfigurableComponent {\n\n private static final Logger s_logger = LoggerFactory.getLogger(SerialExample.class);\n\n private static final String SERIAL_DEVICE_PROP_NAME= \"serial.device\";\n private static final String SERIAL_BAUDRATE_PROP_NAME= \"serial.baudrate\";\n private static final String SERIAL_DATA_BITS_PROP_NAME= \"serial.data-bits\";\n private static final String SERIAL_PARITY_PROP_NAME= \"serial.parity\";\n private static final String SERIAL_STOP_BITS_PROP_NAME= \"serial.stop-bits\";\n\n private ConnectionFactory m_connectionFactory;\n private CommConnection m_commConnection;\n private InputStream m_commIs;\n private OutputStream m_commOs;\n private ScheduledThreadPoolExecutor m_worker;\n private Future<?> m_handle;\n private Map<String, Object> m_properties;\n\n // ----------------------------------------------------------------\n //\n // Dependencies\n //\n // ----------------------------------------------------------------\n public void setConnectionFactory(ConnectionFactory connectionFactory) {\n this.m_connectionFactory = connectionFactory;\n }\n\n public void unsetConnectionFactory(ConnectionFactory connectionFactory) {\n this.m_connectionFactory = null;\n }\n\n // ----------------------------------------------------------------\n //\n // Activation APIs\n //\n // ----------------------------------------------------------------\n\n protected void activate(ComponentContext componentContext, Map<String,Object> properties) {\n s_logger.info(\"Activating SerialExample...\");\n\n m_worker = new ScheduledThreadPoolExecutor(1);\n m_properties = new HashMap<String, Object>();\n doUpdate(properties);\n s_logger.info(\"Activating SerialExample... Done.\");\n }\n\n protected void deactivate(ComponentContext componentContext) {\n s_logger.info(\"Deactivating SerialExample...\");\n\n // shutting down the worker and cleaning up the properties\n m_handle.cancel(true);\n m_worker.shutdownNow();\n //close the serial port\n closePort();\n s_logger.info(\"Deactivating SerialExample... Done.\");\n }\n\n public void updated(Map<String,Object> properties) {\n s_logger.info(\"Updated SerialExample...\");\n\n doUpdate(properties);\n s_logger.info(\"Updated SerialExample... Done.\");\n }\n\n // ----------------------------------------------------------------\n //\n // Private Methods\n //\n // ----------------------------------------------------------------\n\n /**\n * Called after a new set of properties has been configured on the service\n */\n private void doUpdate(Map<String, Object> properties) {\n try {\n for (String s : properties.keySet()) {\n s_logger.info(\"Update - \"+s+\": \"+properties.get(s));\n }\n\n // cancel a current worker handle if one if active\n if (m_handle != null) {\n m_handle.cancel(true);\n }\n\n //close the serial port so it can be reconfigured\n closePort();\n\n //store the properties\n m_properties.clear();\n m_properties.putAll(properties);\n\n //reopen the port with the new configuration\n openPort();\n\n //start the worker thread\n m_handle = m_worker.submit(new Runnable() {\n @Override\n public void run() {\n doSerial();\n }\n });\n\n } catch (Throwable t) {\n s_logger.error(\"Unexpected Throwable\", t);\n }\n }\n\n private void openPort() {\n String port = (String) m_properties.get(SERIAL_DEVICE_PROP_NAME);\n\n if (port == null) {\n s_logger.info(\"Port name not configured\");\n return;\n }\n\n int baudRate = Integer.valueOf((String) m_properties.get(SERIAL_BAUDRATE_PROP_NAME));\n int dataBits = Integer.valueOf((String) m_properties.get(SERIAL_DATA_BITS_PROP_NAME));\n int stopBits = Integer.valueOf((String) m_properties.get(SERIAL_STOP_BITS_PROP_NAME));\n String sParity = (String) m_properties.get(SERIAL_PARITY_PROP_NAME);\n int parity = CommURI.PARITY_NONE;\n\n if (sParity.equals(\"none\")) {\n parity = CommURI.PARITY_NONE;\n } else if (sParity.equals(\"odd\")) {\n parity = CommURI.PARITY_ODD;\n } else if (sParity.equals(\"even\")) {\n parity = CommURI.PARITY_EVEN;\n }\n\n String uri = new CommURI.Builder(port)\n .withBaudRate(baudRate)\n .withDataBits(dataBits)\n .withStopBits(stopBits)\n .withParity(parity)\n .withTimeout(1000)\n .build().toString();\n\n try {\n m_commConnection = (CommConnection) m_connectionFactory.createConnection(uri, 1, false);\n m_commIs = m_commConnection.openInputStream();\n m_commOs = m_commConnection.openOutputStream();\n s_logger.info(port+\" open\");\n } catch (IOException e) {\n s_logger.error(\"Failed to open port \" + port, e);\n cleanupPort();\n }\n }\n\n private void cleanupPort() {\n\n if (m_commIs != null) {\n try {\n s_logger.info(\"Closing port input stream...\");\n m_commIs.close();\n s_logger.info(\"Closed port input stream\");\n } catch (IOException e) {\n s_logger.error(\"Cannot close port input stream\", e);\n }\n m_commIs = null;\n }\n\n if (m_commOs != null) {\n try {\n s_logger.info(\"Closing port output stream...\");\n m_commOs.close();\n s_logger.info(\"Closed port output stream\");\n } catch (IOException e) {\n s_logger.error(\"Cannot close port output stream\", e);\n }\n m_commOs = null;\n }\n\n if (m_commConnection != null) {\n try {\n s_logger.info(\"Closing port...\");\n m_commConnection.close();\n s_logger.info(\"Closed port\");\n } catch (IOException e) {\n s_logger.error(\"Cannot close port\", e);\n }\n m_commConnection = null;\n }\n }\n\n private void closePort() {\n cleanupPort();\n }\n\n private void doSerial() {\n if (m_commIs != null) {\n try {\n int c = -1;\n StringBuilder sb = new StringBuilder();\n while (m_commIs != null) {\n if (m_commIs.available() != 0) {\n c = m_commIs.read();\n } else {\n try {\n Thread.sleep(100);\n continue;\n } catch (InterruptedException e) {\n return;\n }\n }\n\n // on reception of CR, publish the received sentence\n if (c==13) {\n s_logger.debug(\"Received serial input, echoing to output: \" + sb.toString());\n sb.append(\"\\r\\n\");\n String dataRead = sb.toString();\n //echo the data to the output stream\n m_commOs.write(dataRead.getBytes());\n //reset the buffer\n sb = new StringBuilder();\n } else if (c!=10) {\n sb.append((char) c);\n }\n }\n\n } catch (IOException e) {\n s_logger.error(\"Cannot read port\", e);\n } finally {\n try {\n m_commIs.close();\n } catch (IOException e) {\n s_logger.error(\"Cannot close buffered reader\", e);\n }\n }\n }\n }\n}\n
At this point, the bundle implementation is complete. Make sure to save all files before proceeding."},{"location":"java-application-development/how-to-serial-ports/#export-the-bundle","title":"Export the Bundle","text":"To build the Serial Example bundle as a stand-alone OSGi plugin, right-click the project and select Export.
From the wizard, select Plug-in Development | Deployable plug-ins and fragments and click Next.
The Export window appears. Under Available Plug-ins and Fragments, verify that the newly created plug-in is selected.
Under Destination, select the Directory option button and use the Browse button to select an appropriate place to save the JAR file on the local file system.
Info
You will need to know the location where this JAR file is saved for the deployment process.
Under Options, select the checkbox Use class files compiled in the workspace in addition to the checkboxes already enabled, and click Finish.
Doing so will create a JAR file in the selected directory (e.g., /home/joe/myPlugins/plugins/org.eclipse.kura.example.serial_1.0.0.201410311510.jar).
"},{"location":"java-application-development/how-to-serial-ports/#deploy-the-bundle","title":"Deploy the Bundle","text":"In order to proceed, you need to know the IP address of your embedded gateway that is running Kura. Once you have this IP address, follow the mToolkit instructions for installing a single bundle to a remote target device (refer to section 2.03 Testing and Deploying Bundles).
Once the installation successfully completes, you should see a message from the /var/log/kura.log file indicating that the bundle was successfully installed and configured. You can also run this example with the emulator in a Linux or OS X environment as shown sample output below. Make sure that your user account has owner permission for the serial device in /dev.
"},{"location":"java-application-development/how-to-serial-ports/#validate-the-bundle","title":"Validate the Bundle","text":"Next, you need to test that your bundle does indeed echo characters back by opening minicom and configuring it to use [device_node_2] that was previously determined.
Open minicom using the following command at a Linux terminal on the remote gateway device:
minicom -s\n
This command opens a view similar to the following screen capture:
Scroll down to Serial port setup and press . A new dialog window opens as shown below:
Use the minicom menu options on the left (i.e., A, B, C, etc.) to change desired fields. Set the fields to the same values as shown in the previous screen capture except the Serial Device should match the [device_node_2] on your target device. Once this is set, press \\<ENTER> to exit from this menu.
In the main configuration menu, select Exit (do not select the option Exit from Minicom). At this point, you have successfully started minicom on the second serial port attached to your null modem cable allowing minicom to act as a serial device that can send and receive commands to your Kura bundle. You can verify this operation by typing characters and pressing . The function (specifically a \u2018\\n\u2019 character) signals to the Kura application to echo the buffered characters back to the serial device (minicom in this case).
Upon startup, minicom sends an initialization string to the serial device. These characters are sent to the minicom terminal because they were echoed back by Kura listening on the port at the other end of the null modem cable.
When you are done, exit minicom by pressing \u2018 a\u2019, then \u2018q\u2019, and finally \u2018\u2019. Doing so brings you back to the Linux command prompt.
This tutorial instructed you how to write and deploy a Kura bundle on your target device that listens for serial data (coming from the minicom terminal and being received on [device_node_1]). This tutorial also demonstrated that the application echoes data back to the same serial port that is received in minicom, which acts a serial device that sends and receives data. If supported by the device, Kura may send and receive binary data instead of ASCII.
"},{"location":"java-application-development/how-to-use-can-bus/","title":"How to Use CAN bus","text":"The Kura CAN bus protocol implementation is based on the SocketCAN interface, which provides a socket interface to userspace applications. The sockets are designed as can0 and can1. The SocketCAN package is an implementation of Controller Area Network (CAN) protocols. For more information, refer to the following link: https://www.kernel.org/doc/Documentation/networking/can.txt.
"},{"location":"java-application-development/how-to-use-can-bus/#configure-the-can-bus-driver","title":"Configure the CAN bus Driver","text":"The CAN network must be initialized prior to communications. Verify that the CAN driver module has been enabled in the kernel by issuing the following command:
ifconfig -a\n
The connections \u201ccan0\u201d and \u201ccan1\u201d should be displayed. Next, the sockets must be enabled and configured using the following commands (the bitrate value must be set according to the bitrate of the device that will be connected):
ip link set can0 type can bitrate 50000 triple-sampling on\nip link set can0 up\nip link set can1 type can bitrate 50000 triple-sampling on\nip link set can1 up\n
"},{"location":"java-application-development/how-to-use-can-bus/#use-the-can-bus-driver-in-kura","title":"Use the CAN bus Driver in Kura","text":"To use the Can bus Driver in Kura, the bundle org.eclipse.kura.protocol.can must be installed. Refer to the section Application Management for more information.
Once this bundle is installed and verified, the CanConnectionService provides access to basic functionalities of the CAN network, including:
sendCanMessage \u2013 sends an array of bytes in RAW mode.
receiveCanMessage \u2013 reads frames in RAW mode waiting on socket CAN.
Refer to the following Kura javadocs for more information: http://download.eclipse.org/kura/docs/api/5.2.0/apidocs/.
Also, for information about the wrapper that this service utilizes, refer to the following link: https://github.com/entropia/libsocket-can-java.
"},{"location":"java-application-development/how-to-use-dummy-signature-service/","title":"How to use the Dummy Container Signature Validation Service","text":"The Dummy Container Signature Validation Service is an example implementation of the Container Signature Validation Service interface which mainly serves as a reference for future implementations and testing.
The purpose of this component is to have a service whose configuration dictates the signature verification outcome. In the main text area is possible to set the container image reference that the service will report as correctly signed.
The format accepted by the service is: <imageName>:<imageTag>@<imageDigest>
where
<imageName>
: is the container image name. The value will need to be expressed in the form registryURL/imagename in case of a custom registry. Example: nginx
or nvcr.io/nvidia/deepstream
.<imageTag>
: is the container image tag. Example: latest
or 6.4-gc-triton-devel
.<imageDigest>
: is the image digest in the OCI specification format.Each image should be separated by a newline. The service will report a successful signature validation for each image inside its configuration, returning the provided image digest as a result.
"},{"location":"java-application-development/how-to-use-gpio/","title":"How to use GPIO","text":"GPIO resources can be accessed either using the GPIO Service provided by Kura, or directly using the OpenJDK Device I/O embedded library.
"},{"location":"java-application-development/how-to-use-gpio/#gpio-service","title":"GPIO Service","text":"Access to GPIO resources is granted by the GPIOService. Once retrieved, the service can be used to acquire a GPIO Pin and use it as a digital output or a digital input.
The GPIO Service exposes methods to retrieve a GPIO Pin via its name or index as shown below.
KuraGpioPin thePin = gpioServiceInstance.getPinByTerminal(18);\nKuraGpioPin thePin = gpioServiceInstance.getPinByName(\"IgnitionPin\");\n
The KuraGpioPin object is used to manipulate GPIO Pins and exposes methods to read the status of an input, or set the status of digital output as shown below.
//sets digital output value to high\nthePin.setValue(true);\n\n//get value of a digital input pin\nboolean active = thePin.getValue();\n\n//listen for status change on a digital input pin\ntry { \n thePin.addPinStatusListener(new PinStatusListener() {\n @Override \n public void pinStatusChange(boolean value) { \n // Perform tasks when pin status changes \n } \n });\n} catch (KuraClosedDeviceException e) {\n // Here if GPIO cannot be acquired\n } catch (IOException e) {\n // Here on I/O error\n }\n
"},{"location":"java-application-development/how-to-use-gpio/#pin-configuration","title":"Pin Configuration","text":"Pin names, indexes, and configuration are defined in the jdk.dio.properties file.
Although GPIO pins can be accessed with their default configuration, the settings of each pin can be changed when acquiring it with the GPIO Service as shown below.
KuraGpioPin customInputPin = gpioServiceInstance.getPinByTerminal(\n 14, \n KuraGPIODirection.INPUT, \n KuraGPIOMode.INPUT_PULL_UP, \n KuraGPIOTrigger.BOTH_LEVELS);\n
"},{"location":"java-application-development/how-to-use-gpio/#default-configuration","title":"Default Configuration","text":"Default hardware configuration for the hardware platform is defined in the jdk.dio.properties file. Standard configuration for complex devices can be added on a per-device basis as shown below.
#Default PIN configuration. To be overwritten in the following lines\ngpio.GPIOPin = initValue:0, deviceNumber:0, direction:3, mode:-1, trigger:3\n\n#Standard PIN configuration\n64 = deviceType: gpio.GPIOPin, pinNumber:64, name:RELAY1\n
Starting from Kura 5.5.0, the default pin configuration can be described in the form of symbolic links. The syntax is as follows:
/dev/digital_in1 = deviceType: gpio.GPIOPin, direction:0, mode=1, name:digital_in1\n
where /dev/digital_in1
points to /sys/class/gpio/gpioXYZ
. The pin number is set to XYZ and it can be retrieved by name.
Linux-level access in Kura is granted through OpenJDK Device I/O, a third-party library that leverages standard Java ME Device I/O APIs to Java SE. Kura is distributed with the relevant native libraries, together with the default hardware configuration, for each platform on which it runs.
I2C, SPI, and GPIO resources can be directly accessed through the jdk.dio library present in the target platform.
"},{"location":"java-application-development/how-to-use-gpio/#apis","title":"APIs","text":"Kura supports the full set of APIs for the listed device types. Refer to References for further API information.
"},{"location":"java-application-development/how-to-use-gpio/#accessing-a-gpio-pin-with-openjdk-device-io","title":"Accessing a GPIO Pin with OpenJDK Device I/O","text":"A GPIO Pin can be accessed by referencing its index in the properties file, or by creating a Pin configuration object and feeding it to the DeviceManager as shown in the code examples below.
"},{"location":"java-application-development/how-to-use-gpio/#accessing-a-gpio-pin-by-its-index","title":"Accessing a GPIO Pin by its Index","text":"#Accessing the GPIO Pin number 17. The default behaviour is defined in the\n#jdk.dio.properties file\n#\n#i.e.:\n# gpio.GPIOPin = initValue:0, deviceNumber:0, direction:3, mode:-1, trigger:3\n# 17 = deviceType: gpio.GPIOPin, pinNumber:17, name:GPIO_USER_1\n\nGPIOPin led = (GPIOPin)DeviceManager.open(17);\n\nled.setValue(true) //Turns the LED on\nled.setValue(false) //Turns the LED off\nboolean status = led.getValue() //true if the LED is on\n
"},{"location":"java-application-development/how-to-use-gpio/#accessing-a-gpio-pin-using-a-device-configuration-object","title":"Accessing a GPIO Pin Using a Device Configuration Object","text":"#Accessing the Pin number 17 with custom configuration\n\nGPIOPinConfig pinConfig = new GPIOPinConfig(\n DeviceConfig.DEFAULT, //GPIO Controller number or name\n 17, //GPIO Pin number\n GPIOPinConfig.DIR_INPUT_ONLY, //Pin direction\n GPIOPinConfig.MODE_INPUT_PULL_DOWN, //Pin resistor\n GPIOPinConfig.TRIGGER_BOTH_EDGES, //Triggers\n false //initial value (for outputs)\n);\n\nGPIOPin button = (GPIOPin) DeviceManager.open(GPIOPin.class, pinConfig);\n\nbutton.setInputListener(new PinListener(){\n @Override\n public void valueChanged(PinEvent event) {\n System.out.println(\"PIN Status Changed!\");\n System.out.println(event.getLastTimeStamp() + \" - \" + event.getValue());\n }\n});\n
"},{"location":"java-application-development/how-to-use-legacy-bt-beacon-scanner/","title":"How to Use Legacy Bluetooth LE Beacon Scanner","text":"Warning
This guide uses the deprecated Kura Bluetooth APIs. Please consider to use the new ones.
"},{"location":"java-application-development/how-to-use-legacy-bt-beacon-scanner/#overview","title":"Overview","text":"The Bluetooth Beacon Scanner example is a bundle for Eclipse Kura that uses the Bluetooth LE service to search for near Beacon devices. A Beacon device is a Bluetooth Low Energy device that broadcasts its identity to nearby devices. It uses a specific BLE packet, called beacon or advertising packet, that contains the following information:
Proximity UUID - a 128-bit value that uniquely identifies one or more beacons as a certain type or from a certain organization.
Major value - an optional 16-bit unsigned integer that can group related beacons with the same proximity UUID.
Minor value - an optional 16-bit unsigned integer that differentiates beacons with the same proximity UUID and major value.
Tx Power - a value programmed into the beacon that enables distance from the beacon to be determined based on signal strength.
The Beacon Scanner bundle is configured with a Company Code in order to filter the near beacons. So, only beacons with a specific Company Code are discovered by the bundle and their information are reported. Moreover the bundle is able to roughly estimate the distance from the beacon.
For further information about the Beacons, please refer to the BLE Beacon Example.
"},{"location":"java-application-development/how-to-use-legacy-bt-beacon-scanner/#prerequisites","title":"Prerequisites","text":"Development Environment Setup
Hardware
Embedded device running Kura with Bluetooth 4.0 (LE) capabilities.
bluez_ packet must be installed on the embedded device. Follow the installation instructions in How to Use Bluetooth LE.
For this tutorial a Raspberry Pi Type B with a LMTechnologies LM506 Bluetooth 4.0 dongle is used.
"},{"location":"java-application-development/how-to-use-legacy-bt-beacon-scanner/#beacon-scanning-with-kura","title":"Beacon Scanning with Kura","text":"The Beacon Scanner bundle is a Kura example that allows you to configure the Company Code for the Beacon filtering and to start/stop the scanner procedure.
"},{"location":"java-application-development/how-to-use-legacy-bt-beacon-scanner/#develop-the-beacon-scanner-bundle","title":"Develop the Beacon Scanner Bundle","text":"The Beacon Scanner bundle code development follows the guidelines presented in the Hello World Application :
Create a Plug-in Project named org.eclipse.kura.example.beacon.scanner.
Create the class BeaconScannerExample.
Include the following bundles in the MANIFEST.MF:
The following files need to be implemented in order to write the source code:
META-INF/MANIFEST.MF - OSGI manifest that describes the bundle and its dependencies.
OSGI-INF/beaconExample.xml - declarative services definition that describes the services exposed and consumed by this bundle.
OSGI-INF/metatype/org.eclipse.kura.example.beacon.scanner.BeaconScannerExample.xml - configuration description of the bundle and its parameters, types, and defaults.
org.eclipse.kura.example.beacon.scanner.BeaconScannerExample.java - main implementation class.
The OSGI-INF/metatype/org.eclipse.kura.example.beacon.scanner.BeaconScannerExample.xml file describes the parameters for this bundle including the following:
enableScanning - enables Beacon scanning.
companyCode - defines a 16-bit company code as hex string.
iname - provides the name of bluetooth adapter.
The com.eurotech.example.beacon.scanner.BeaconScannerExample.java file contains the activate, deactivate and updated methods for this bundle. The activate and updated methods gets the properties from the configurable component and, if the scanning is enabled, call the setup private method. This method gets the BluetoothAdapter, enables the interface if needed, and starts the scan calling the bluetootAdapter.startBeaconScan(companyCode, listener) method. The arguments of the method are the companyCode and a listener that is notified when a device is detected. In this case the BeaconScannerExample class implements BluetoothBeaconScanListener. The following code sample shows the setup method:
private void setup() {\n\n this.publishTimes = new HashMap<String, Long>();\n\n this.bluetoothAdapter = this.bluetoothService.getBluetoothAdapter(this.adapterName);\n if (this.bluetoothAdapter != null) {\n this.bluetoothAdapter.startBeaconScan(this.companyCode, this);\n }\n\n}\n
Since BeaconScannerExample implements BluetoothBeaconScanListener, the onBeaconDataReceived method must be overridden. When a device is detected, the listener is notified and the onBeaconDataReceived method is called with a BluetoothBeaconData object. The BluetoothBeaconData class contains the following fields:
uuid - a 128-bit value that uniquely identifies one or more beacons as a certain type or from a certain organization.
address - the source of the beacon
major - an optional 16-bit unsigned integer that can group related beacons with the same proximity UUID.
minor - an optional 16-bit unsigned integer that differentiates beacons with the same proximity UUID and major value.
rssi - the Received Signal Strength Indication
txpower - a value programmed into the beacon that enables distance from the beacon to be determined based on signal strength.
The following code is an implementation of onBeaconDataReceived that logs the BluetoothBeaconData fields:
public void onBeaconDataReceived(BluetoothBeaconData beaconData) {\n\n logger.debug(\"Beacon from {} detected.\", beaconData.address);\n long now = System.nanoTime();\n\n Long lastPublishTime = this.publishTimes.get(beaconData.address);\n\n // If this beacon is new, or it last published more than 'rateLimit' ms ago\n if (lastPublishTime == null || (now - lastPublishTime) / 1000000L > this.rateLimit) {\n\n // Store the publish time against the address\n this.publishTimes.put(beaconData.address, now);\n if (this.cloudPublisher == null) {\n logger.info(\"No cloud publisher selected. Cannot publish!\");\n return;\n }\n\n // Publish the beacon data to the beacon's topic\n KuraPayload kp = new KuraPayload();\n kp.setTimestamp(new Date());\n kp.addMetric(\"uuid\", beaconData.uuid);\n kp.addMetric(\"txpower\", beaconData.txpower);\n kp.addMetric(\"rssi\", beaconData.rssi);\n kp.addMetric(\"major\", beaconData.major);\n kp.addMetric(\"minor\", beaconData.minor);\n kp.addMetric(\"distance\", calculateDistance(beaconData.rssi, beaconData.txpower));\n\n Map<String, Object> properties = new HashMap<String, Object>();\n properties.put(\"address\", beaconData.address);\n KuraMessage message = new KuraMessage(kp, properties);\n try {\n this.cloudPublisher.publish(message);\n } catch (KuraException e) {\n logger.error(\"Unable to publish\", e);\n }\n }\n}\n
Finally, the Beacon Scanner is able to roughly estimate the distance of the detected beacon using the calculateDistance method:
private double calculateDistance(int rssi, int txpower) {\n\n double distance;\n\n int ratioDB = txpower - rssi;\n double ratioLinear = Math.pow(10, (double) ratioDB / 10);\n distance = Math.sqrt(ratioLinear);\n\n return distance;\n}\n
"},{"location":"java-application-development/how-to-use-legacy-bt-beacon-scanner/#deploy-and-validate-the-bundle","title":"Deploy and Validate the Bundle","text":"In order to proceed, you need to know the IP address of your embedded gateway that is on the remote target unit. With this information, follow the mToolkit instructions for installing a single bundle to the remote target device located here. When the installation is complete, the bundle starts automatically.
In the Kura Gateway Administration Console, the BeaconScannerExample tab appears on the left and enables the device to be configured for scanning.
You should see a message similar to the one below from /var/log/kura.log indicating that the bundle was successfully installed and configured.
2016-08-08 14:39:48,351 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.s.BeaconScannerExample - Activating Bluetooth Beacon Scanner example...\n2016-08-08 14:39:48,353 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.s.BeaconScannerExample - Activating Bluetooth Beacon Scanner example...Done\n2016-08-08 14:39:48,373 [Component Resolve Thread (Bundle 6)] INFO o.e.k.c.c.ConfigurableComponentTracker - Adding ConfigurableComponent with pid org.eclipse.kura.example.beacon.scanner.BeaconScannerExample, service pid org.eclipse.kura.example.beacon.scanner.BeaconScannerExample and factory pid null\n2016-08-08 14:39:48,373 [Component Resolve Thread (Bundle 6)] INFO o.e.k.c.c.ConfigurationServiceImpl - Registration of ConfigurableComponent org.eclipse.kura.example.beacon.scanner.BeaconScannerExample by org.eclipse.kura.core.configuration.ConfigurationServiceImpl@1197c95...\n2016-08-08 14:40:40,186 [qtp23115489-40] WARN o.e.k.w.s.s.SkinServlet - Resource File /opt/eclipse/kura/console/skin/skin.js does not exist\n2016-08-08 14:40:56,996 [qtp23115489-42] INFO o.e.k.c.c.ConfigurationServiceImpl - Loading init configurations from: 1470667042563...\n2016-08-08 14:40:57,679 [qtp23115489-42] INFO o.e.k.c.c.ConfigurationServiceImpl - Merging configuration for pid: org.eclipse.kura.example.beacon.scanner.BeaconScannerExample\n2016-08-08 14:40:57,687 [qtp23115489-42] INFO o.e.k.c.c.ConfigurationServiceImpl - Updating Configuration of ConfigurableComponent org.eclipse.kura.example.beacon.scanner.BeaconScannerExample ... Done.\n2016-08-08 14:40:57,689 [qtp23115489-42] INFO o.e.k.c.c.ConfigurationServiceImpl - Writing snapshot - Saving /opt/eclipse/kura/data/snapshots/snapshot_1470667257688.xml...\n2016-08-08 14:40:57,914 [qtp23115489-42] INFO o.e.k.c.c.ConfigurationServiceImpl - Writing snapshot - Saving /opt/eclipse/kura/data/snapshots/snapshot_1470667257688.xml... Done.\n2016-08-08 14:40:57,916 [qtp23115489-42] INFO o.e.k.c.c.ConfigurationServiceImpl - Snapshots Garbage Collector. Deleting /opt/eclipse/kura/data/snapshots/snapshot_1470651681077.xml\n2016-08-08 14:40:58,013 [Component Resolve Thread (Bundle 6)] INFO o.e.k.l.b.l.BluetoothLeScanner - Starting bluetooth le beacon scan...\n
Using a device equipped with Kura acting as a Beacon (see BLE Beacon Example), the following lines appear on the log file when the device is detected:
2016-08-08 14:49:03,487 [BluetoothProcess BTSnoop Gobbler] INFO o.e.k.e.b.s.BeaconScannerExample - UUID : AAAAAAAABBBBCCCCDDDDEEEEEEEEEEEE\n2016-08-08 14:49:03,488 [BluetoothProcess BTSnoop Gobbler] INFO o.e.k.e.b.s.BeaconScannerExample - TxPower : -58\n2016-08-08 14:49:03,488 [BluetoothProcess BTSnoop Gobbler] INFO o.e.k.e.b.s.BeaconScannerExample - RSSI : -55\n2016-08-08 14:49:03,489 [BluetoothProcess BTSnoop Gobbler] INFO o.e.k.e.b.s.BeaconScannerExample - Major : 0\n2016-08-08 14:49:03,489 [BluetoothProcess BTSnoop Gobbler] INFO o.e.k.e.b.s.BeaconScannerExample - Minor : 0\n2016-08-08 14:49:03,490 [BluetoothProcess BTSnoop Gobbler] INFO o.e.k.e.b.s.BeaconScannerExample - Address : 5C:F3:70:60:63:8F\n2016-08-08 14:49:03,490 [BluetoothProcess BTSnoop Gobbler] INFO o.e.k.e.b.s.BeaconScannerExample - Distance : 0.7079457843841379\n
"},{"location":"java-application-development/how-to-use-legacy-bt-le-beacons/","title":"How to Use Legacy Bluetooth LE Beacons","text":"Warning
This guide uses the deprecated Kura Bluetooth APIs. Please consider to use the new ones.
"},{"location":"java-application-development/how-to-use-legacy-bt-le-beacons/#overview","title":"Overview","text":"The Bluetooth Beacon example is a simple bundle for Eclipse Kura that allows you to configure a device as a Beacon. A Beacon device is a Bluetooth Low Energy device that broadcasts its identity to nearby devices. It uses a specific BLE packet, called beacon or advertising packet, that contains the following information:
Proximity UUID - a 128-bit value that uniquely identifies one or more beacons as a certain type or from a certain organization.
Major value - an optional 16-bit unsigned integer that can group related beacons with the same proximity UUID.
Minor value - an optional 16-bit unsigned integer that differentiates beacons with the same proximity UUID and major value.
Tx Power - a value programmed into the beacon that enables distance from the beacon to be determined based on signal strength.
The advertising packet has a fixed format and is broadcasted periodically. The information contained in the advertising packet can be used by a receiver, typically a smartphone, to identify the beacon and to roughly estimate its distance.
"},{"location":"java-application-development/how-to-use-legacy-bt-le-beacons/#prerequisites","title":"Prerequisites","text":"Development Environment Setup
Hardware
Embedded device running Kura with Bluetooth 4.0 (LE) capabilities.
bluez_ packet must be installed on the embedded device. Follow the installation instructions in How to Use Bluetooth LE.
For this tutorial a Raspberry Pi Type B with a LMTechnologies LM506 Bluetooth 4.0 dongle is used.
"},{"location":"java-application-development/how-to-use-legacy-bt-le-beacons/#beacon-advertising-with-hcitool","title":"Beacon Advertising with hcitool","text":"After the embedded device is properly configured, the advertising may be started using the hcitool command contained in the bluez packet.
Plug in the Bluetooth dongle if needed and verify that the interface is up with the following command:
sudo hciconfig hci0\n
If the interface is down, enable it with the following command:
sudo hciconfig hci0 up\n
To configure the advertising packet, enter the following command:
sudo hcitool -i hci0 cmd 0x08 0x0008 1e 02 01 1a 1a ff 4c 00 02 15 aa aa aa aa bb bb cc cc dd dd ee ee ee ee ee ee 01 00 01 00 c5\n
In this example, the packet will contain the uuid aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee, major 1, minor 1 and Tx Power -59 dBm.
For further information about BLE commands and packet formats, refer to the Bluetooth 4.0 Core specifications
To set the advertising interval to 1 second, enter the following command:
sudo hcitool -i hci0 cmd 0x08 0x0006 a0 00 a0 00 03 00 00 00 00 00 00 00 00 07 00\n
Finally, to start the advertising, enter the following command:
sudo hcitool -i hci0 cmd 0x08 0x000a 01\n
To verify that the embedded device is broadcasting its beacon, use a smartphone with a iBeacon scanner app (e.g., iBeacon Finder, iBeacon Scanner, or iBeaconDetector on Android). To stop the advertising, write 0 to the register 0x000a as shown in the following command:
sudo hcitool -i hci0 cmd 0x08 0x000a 00\n
"},{"location":"java-application-development/how-to-use-legacy-bt-le-beacons/#beacon-advertising-with-kura","title":"Beacon Advertising with Kura","text":"The Beacon bundle is a simple example that allows you to configure the advertising packet, the time interval, and to start/stop the advertising.
"},{"location":"java-application-development/how-to-use-legacy-bt-le-beacons/#develop-the-beacon-bundle","title":"Develop the Beacon Bundle","text":"The Beacon bundle code development follows the guidelines presented in the Hello World Application :
Create a Plug-in Project named org.eclipse.kura.example.beacon.
Create the class BeaconExample.
Include the following bundles in the MANIFEST.MF:
The following files need to be implemented in order to write the source code:
META-INF/MANIFEST.MF - OSGI manifest that describes the bundle and its dependencies.
OSGI-INF/beaconExample.xml - declarative services definition that describes the services exposed and consumed by this bundle.
OSGI-INF/metatype/org.eclipse.kura.example.beacon.BeaconExample.xml - configuration description of the bundle and its parameters, types, and defaults.
org.eclipse.kura.example.beacon.BeaconExample.java - main implementation class.
The OSGI-INF/metatype/org.eclipse.kura.example.beacon.beaconExample.xml file describes the parameters for this bundle including the following:
enableAdvertising - enables Beacon advertising.
minBeaconInterval - sets the minimum time interval between beacons (milliseconds).
maxBeaconInterval - sets the maximum time interval between beacons (milliseconds).
uuid - defines a 128-bit uuid for beacon advertising expressed as hex string.
major - sets the major value.
minor - sets the minor value.
companyCode - defines a 16-bit company code as hex string.
txPower - indicates the transmission power measured at 1m away from the beacon expressed in dBm.
LELimited - defines the LE Discoverable Mode. Set false to advertise for 30.72s and then stops. Set true to advertise indefinitely.
BR_EDRSupported - indicates whether BR/EDR is supported.
LE_BRController - indicates whether LE and BR/EDR Controller operates simultaneously.
LE_BRHost - indicates whether LE and BR/EDR Host operates simultaneously.
iname - provides the name of bluetooth adapter.
The com.eurotech.example.beacon.BeaconExample.java file contains the activate and deactivate methods for this bundle. The activate method gets the BluetoothAdapter, enables the interface if needed, and executes the configureBeacon method that configures the device according to the properties. The following code sample shows part of the activate method:
// Get Bluetooth adapter with Beacon capabilities and ensure it is enabled\nthis.bluetoothAdapter = this.bluetoothService.getBluetoothAdapter(this.name, this);\nif (this.bluetoothAdapter != null) {\n logger.info(\"Bluetooth adapter interface => {}\", this.name);\n logger.info(\"Bluetooth adapter address => {}\", this.bluetoothAdapter.getAddress());\n logger.info(\"Bluetooth adapter le enabled => {}\", this.bluetoothAdapter.isLeReady());\n\n if (!this.bluetoothAdapter.isEnabled()) {\n logger.info(\"Enabling bluetooth adapter...\");\n this.bluetoothAdapter.enable();\n logger.info(\"Bluetooth adapter address => {}\", this.bluetoothAdapter.getAddress());\n }\n\n configureBeacon();\n\n} else {\n logger.warn(\"No Bluetooth adapter found ...\");\n}\n
The configureBeacon (shown below) is a private method:
private void configureBeacon() {\n\n if (this.enable) {\n\n if (this.minInterval != null && this.maxInterval != null) {\n this.bluetoothAdapter.setBeaconAdvertisingInterval(this.minInterval, this.maxInterval);\n }\n this.bluetoothAdapter.startBeaconAdvertising();\n if (this.uuid != null && this.major != null && this.minor != null && this.companyCode != null\n && this.txPower != null) {\n this.bluetoothAdapter.setBeaconAdvertisingData(this.uuid, this.major, this.minor, this.companyCode,\n this.txPower, this.leLimited, this.leLimited ? false : true, this.brSupported,\n this.brController, this.brHost);\n }\n } else {\n this.bluetoothAdapter.stopBeaconAdvertising();\n }\n}\n
"},{"location":"java-application-development/how-to-use-legacy-bt-le-beacons/#deploy-and-validate-the-bundle","title":"Deploy and Validate the Bundle","text":"In order to proceed, you need to know the IP address of your embedded gateway that is on the remote target unit. With this information, follow the mToolkit instructions for installing a single bundle to the remote target device located here. When the installation is complete, the bundle starts automatically.
In the Kura Gateway Administration Console, the BeaconExample tab appears on the left and enables the beacon to be configured for advertising.
You should see a message similar to the one below from /var/log/kura.log indicating that the bundle was successfully installed and configured.
2015-07-09 10:46:06,522 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.BeaconExample - Activating Bluetooth Beacon example...\n2015-07-09 10:46:06,639 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.BeaconExample - Bluetooth adapter interface => hci0\n2015-07-09 10:46:06,643 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.BeaconExample - Bluetooth adapter address => null\n2015-07-09 10:46:06,645 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.BeaconExample - Bluetooth adapter le enabled => false\n2015-07-09 10:46:06,664 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.BeaconExample - Enabling bluetooth adapter...\n2015-07-09 10:46:06,745 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.BeaconExample - Bluetooth adapter address => 5C:F3:70:60:63:9E\n2015-07-09 10:46:06,770 [Component Resolve Thread (Bundle 6)] INFO o.e.k.l.b.BluetoothAdapterImpl - Set Advertising Parameters on interface hci0\n2015-07-09 10:46:06,842 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.b.BluetoothBeaconListener - Command ogf 0x08, ocf 0x0006 Succeeded.\n2015-07-09 10:46:06,852 [Component Resolve Thread (Bundle 6)] INFO o.e.k.l.b.BluetoothAdapterImpl - Set Advertising Data on interface hci0\n2015-07-09 10:46:06,859 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.BeaconExample - Command results : 01 06 20 00\n2015-07-09 10:46:06,872 [Component Resolve Thread (Bundle 6)] INFO o.e.k.l.b.BluetoothAdapterImpl - Start Advertising on interface hci0\n2015-07-09 10:46:06,906 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.b.BluetoothBeaconListener - Command ogf 0x08, ocf 0x0008 Succeeded.\n2015-07-09 10:46:06,908 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.BeaconExample - Command results : 01 08 20 00\n2015-07-09 10:46:06,921 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.b.BluetoothBeaconListener - Command ogf 0x08, ocf 0x000a Succeeded.\n2015-07-09 10:46:06,923 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.BeaconExample - Command results : 01 0A 20 00\n2015-07-09 10:46:06,947 [Component Resolve Thread (Bundle 6)] INFO o.e.k.c.c.ConfigurableComponentTracker - Adding ConfigurableComponent org.eclipse.kura.example.beacon.BeaconExample\n2015-07-09 10:46:06,950 [Component Resolve Thread (Bundle 6)] INFO o.e.k.c.c.ConfigurationServiceImpl - Registration of ConfigurableComponent org.eclipse.kura.example.beacon.BeaconExample by org.eclipse.kura.core.configuration.ConfigurationServiceImpl@11120b6...\n2015-07-09 10:46:06,996 [Component Resolve Thread (Bundle 6)] INFO o.e.k.c.c.ConfigurationServiceImpl - Registering org.eclipse.kura.example.beacon.BeaconExample with ocd: org.eclipse.kura.core.configuration.metatype.Tocd@8af8b3 ...\n2015-07-09 10:46:06,999 [Component Resolve Thread (Bundle 6)] INFO o.e.k.c.c.ConfigurationServiceImpl - Registration Completed for Component org.eclipse.kura.example.beacon.BeaconExample.\n
Note that the bundle writes the string returned by the configuration commands to the log:
2015-07-09 10:46:06,859 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.BeaconExample - Command results : 01 06 20 00\n
The last number of the string is the error code. A value of \"00\" indicates a successful command. Refer to the Bluetooth 4.0 Core specifications for a complete list of the error codes.
Once the bundle is deployed, you can use a iBeacon scanner app to detect the bundle. Also, you can modify the bundle properties and verify the results in the scanner.
"},{"location":"java-application-development/how-to-use-legacy-bt-le/","title":"How to Use Legacy Bluetooth LE","text":"Warning
This guide uses the deprecated Kura Bluetooth APIs. Please consider to use the new ones.
"},{"location":"java-application-development/how-to-use-legacy-bt-le/#overview","title":"Overview","text":"This section provides an example of how to develop a simple bundle that discovers and connects to a Smart device (BLE), retrieves data from it, and publishes the results to the cloud. This example uses the TI SensorTag based on CC2541 or CC2650. For more information about this device, refer to https://www.ti.com/tool/cc2541dk-sensor and https://www.ti.com/tool/TIDC-CC2650STK-SENSORTAG.
You will learn how to perform the following functions:
Prepare the embedded device to communicate with a Smart device
Develop a bundle retrieves data from the device
Optionally publish the data in the cloud
Setting up Kura Development Environment
Hardware
Use an embedded device running Kura with Bluetooth 4.0 (LE) capabilities
This tutorial uses a Raspberry Pi Type B with a LMTechnologies LM506 Bluetooth 4.0 dongle.
"},{"location":"java-application-development/how-to-use-legacy-bt-le/#prepare-the-embedded-device","title":"Prepare the Embedded Device","text":"In order to communicate with Smart devices, the bluez package must be installed on the embedded device. To do so, make sure you have the necessary libraries on the Raspberry Pi and proceed as follows:
sudo apt-get install libusb-dev libdbus-1-dev libglib2.0-dev libudev-dev libical-dev libreadline-dev\n
Next, download and uncompress the package:
sudo wget https://www.kernel.org/pub/linux/bluetooth/bluez-4.101.tar.xz\nsudo tar xvf bluez-4.101.tar\n
Change to the blues folder, and then configure and install the package:
cd bluez-4.101\nsudo ./configure --disable-systemd --enable-tools\nsudo make\nsudo make install\n
Finally, change the location of the hciconfig and gatttool commands:
sudo mv /usr/local/sbin/hciconfig /usr/sbin\nsudo mv /usr/local/bin/gatttool /usr/sbin\n
Info
Both bluez 4.101 and 5.XX are supported.
"},{"location":"java-application-development/how-to-use-legacy-bt-le/#sensortag-communication-via-command-line","title":"SensorTag Communication via Command Line","text":"Once configured, you can scan and connect with a Smart device. A TI SensorTag is used in the example that follows.
Plug in the Bluetooth dongle if needed and verify that the interface is up:
sudo hciconfig hci0\n
If the interface is down, enable it with the following command:
sudo hciconfig hci0 up\n
Perform a BLE scan with hcitool (this process may be interrupted with ctrl-c):
sudo hcitool lescan\nLE Scan ...\nBC:6A:29:AE:CC:96 (unknown)\nBC:6A:29:AE:CC:96 SensorTag\n
If the SensorTag is not listed, press the button on the left side of the device to make it discoverable. Interactive communication with the device is possible using the gatttool:
sudo gatttool -b BC:6A:29:AE:CC:96 -I\n[ ][BC:6A:29:AE:CC:96][LE]> connect\n[CON][BC:6A:29:AE:CC:96][LE]>\n
If the output of the connect command is
connect: Connection refused (111)\n
then you have to enable LE capabilities on your BT interface: cd bluez-4.101/mgmt\nsudo ./btmgmt le on\n
In order to read the sensor values from the SensorTag, you need to write some registers on the device. The example that follows shows the procedure for retrieving the temperature value from the SensorTag based on the CC2541.
Once connected with gatttool, the IR temperature sensor is enabled to write the value 01 to the handle 0x0029:
[CON][BC:6A:29:AE:CC:96][LE]> char-write-cmd 0x0029 01\n
Next, the temperature value is read from the 0x0025 handle:
[CON][BC:6A:29:AE:CC:96][LE]> char-read-hnd 0x0025\n[CON][BC:6A:29:AE:CC:96][LE]>\nCharacteristic value/descriptor: a7 fe 2c 0d\",\n
In accordance with the documentation, the retrieved raw values have to be refined in order to obtain the ambient and object temperature.
Enable notifications writing the value 0001 to the 0x0026 register:
[CON][BC:6A:29:AE:CC:96][LE]> char-write-cmd 0x0026 0100\n[CON][BC:6A:29:AE:CC:96][LE]>\nNotification handle = 0x0025 value: a5 fe 3c 0d\n[CON][BC:6A:29:AE:CC:96][LE]>\nNotification handle = 0x0025 value: 9f fe 3c 0d\n[CON][BC:6A:29:AE:CC:96][LE]>\nNotification handle = 0x0025 value: 9a fe 3c 0d\n
Stop the notifications by writing 0000 to the same register:
[CON][BC:6A:29:AE:CC:96][LE]>\nNotification handle = 0x0025 value: 9e fe 3c 0d\n[CON][BC:6A:29:AE:CC:96][LE]> char-write-cmd 0x0026 0000\nNotification handle = 0x0025 value: a3 fe 3c 0d\n[CON][BC:6A:29:AE:CC:96][LE]>\n
Info
bluez 5.XX comes with the bluetoothctl tool that can be used in place of hcitool and gatttool. Please refer to the man page and help for more details.
"},{"location":"java-application-development/how-to-use-legacy-bt-le/#ble-bundle-for-ti-sensortag","title":"BLE Bundle for TI SensorTag","text":"The BLE bundle performs the following operations:
Starts a scan for smart devices (lescan)
Selects all the TI SensorTag in range
Connects to the discovered SensorTags and discovers their capabilities
Reads data from all the sensors onboard and writes the values in the log file
Warning
The Legacy Bluetooth LE Example supports TI SensorTag CC2541 (all firmware versions) and CC2650 (firmware version above 1.20)
"},{"location":"java-application-development/how-to-use-legacy-bt-le/#develop-the-ble-bundle","title":"Develop the BLE Bundle","text":"Once the required packages are installed and communication with the SensorTag via command line is established, you may start to develop the BLE bundle. For more detailed information about bundle development (i.e., the plug-in project, classes, and MANIFEST file configuration), please refer to the Hello World Application.
Create a Plug-in Project named org.eclipse.kura.example.ble.tisensortag.
Create the following classes: BluetoothLe, TiSensorTag, and TiSensorTagGatt.
Include the following bundles in the MANIFEST.MF:
The following files need to be implemented in order to write the source code:
META-INF/MANIFEST.MF - OSGI manifest that describes the bundle and its dependencies.
OSGI-INF/bleExample.xml - declarative services definition that describes the services exposed and consumed by this bundle.
OSGI-INF/metatype/org.eclipse.kura.example.ble.tisensortag.BluetoothLe.xml - configuration description of the bundle and its parameters, types, and defaults.
org.eclipse.kura.example.ble.tisensortag.BluetoothLe.java - main implementation class.
org.eclipse.kura.example.ble.tisensortag.TiSensorTag.java - class used to connect with a TI SensorTag.
org.eclipse.kura.example.ble.tisensortag.TiSensorTagGatt.java - class that describes all the handles and UUIDs to access to the SensorTag sensors.
The OSGI-INF/metatype/org.eclipse.kura.example.ble.tisensortag.BluetoothLe.xml file describes the parameters for this bundle including the following:
scan_time - specifies the length of time to scan for devices in seconds.
period - specifies the time interval in seconds between two publishes.
enableTermometer - Enable temperature sensor.
enableAccelerometer - Enable accelerometer sensor.
...
publishTopic - supplies the topic to publish data to the cloud.
iname - Name of bluetooth adapter.
The org.eclipse.kura.example.ble.tisensortag.BluetoothLe.java file contains the activate, deactivate and updated methods for this bundle. The activate and update methods gets the BluetoothAdapter and schedules the execution of the performScan method every second and readTiSensorTags every user defined period. The following code sample shows part of the code:
this.options = new BluetoothLeOptions(properties);\nthis.startTime = 0;\nif (this.options.isEnableScan()) {\n // re-create the worker\n this.worker = Executors.newScheduledThreadPool(2);\n\n // Get Bluetooth adapter and ensure it is enabled\n this.bluetoothAdapter = this.bluetoothService.getBluetoothAdapter(this.options.getIname());\n if (this.bluetoothAdapter != null) {\n logger.info(\"Bluetooth adapter interface => {}\", this.options.getIname());\n if (!this.bluetoothAdapter.isEnabled()) {\n logger.info(\"Enabling bluetooth adapter...\");\n this.bluetoothAdapter.enable();\n }\n logger.info(\"Bluetooth adapter address => {}\", this.bluetoothAdapter.getAddress());\n\n this.scanHandle = this.worker.scheduleAtFixedRate(this::performScan, 0, 1, TimeUnit.SECONDS);\n this.readHandle = this.worker.scheduleAtFixedRate(this::readTiSensorTags, 0, this.options.getPeriod(),\n TimeUnit.SECONDS);\n } else {\n logger.info(\"Bluetooth adapter {} not found.\", this.options.getIname());\n }\n}\n
The performScan method manages the start and stop of the scanning procedure as shown below.
void performScan() {\n\n // Scan for devices\n if (this.bluetoothAdapter.isScanning()) {\n logger.info(\"bluetoothAdapter.isScanning\");\n if (System.currentTimeMillis() - this.startTime >= this.options.getScantime() * 1000) {\n this.bluetoothAdapter.killLeScan();\n }\n } else {\n if (System.currentTimeMillis() - this.startTime >= this.options.getPeriod() * 1000) {\n logger.info(\"startLeScan\");\n this.bluetoothAdapter.startLeScan(this);\n this.startTime = System.currentTimeMillis();\n }\n }\n\n}\n
The BluetoothLe class implements the org.eclipse.kura.bluetooth.BluetoothLeScanListener interface and the onScanResults method is called when the scan procedure ends. The method filters the scan results and stores the SensorTag devices in a list. Part of the onScanResults method is shown below.
@Override\n public void onScanResults(List<BluetoothDevice> scanResults) {\n\n // Scan for TI SensorTag\n for (BluetoothDevice bluetoothDevice : scanResults) {\n logger.info(\"Address {} Name {}\", bluetoothDevice.getAdress(), bluetoothDevice.getName());\n\n if (bluetoothDevice.getName().contains(\"SensorTag\") && !isSensorTagInList(bluetoothDevice.getAdress())) {\n this.tiSensorTagList.add(new TiSensorTag(bluetoothDevice));\n }\n }\n\n }\n
The readTiSensorTags is responsible to read the sensors for all the SensorTags contained in the list and publish the resulting data.
private void readTiSensorTags() {\n // connect to TiSensorTags\n this.tiSensorTagList.forEach(myTiSensorTag -> {\n connect(myTiSensorTag);\n\n if (myTiSensorTag.isConnected()) {\n ...\n\n KuraPayload payload = new KuraPayload();\n payload.setTimestamp(new Date());\n payload.addMetric(\"Firmware\", myTiSensorTag.getFirmwareRevision());\n if (myTiSensorTag.isCC2650()) {\n payload.addMetric(\"Type\", \"CC2650\");\n } else {\n payload.addMetric(\"Type\", \"CC2541\");\n }\n readServicesAndCharacteristics(myTiSensorTag);\n readSensors(myTiSensorTag, payload);\n myTiSensorTag.enableIOService();\n\n publishData(myTiSensorTag, payload);\n\n ...\n } else {\n logger.warn(\"Cannot connect to TI SensorTag {}.\", myTiSensorTag.getBluetoothDevice().getAdress());\n }\n });\n\n}\n
Since it is not possible to poll the status of the buttons on the SensorTag, the BLE example enables the notifications for them.
"},{"location":"java-application-development/how-to-use-legacy-bt-le/#orgeclipsekuraexampleblesensortagtisensortagjava-file","title":"org.eclipse.kura.example.ble.sensortag.TiSensorTag.java File","text":"The org.eclipse.kura.example.ble.sensortag.TiSensorTag class is used to connect and disconnect to the SensorTag. It also contains the methods to configure and read data from the sensor. The connection method uses the BluetoothGatt Service as shown below:
public boolean connect(String adapterName) {\n this.bluetoothGatt = this.device.getBluetoothGatt();\n boolean connected = false;\n try {\n connected = this.bluetoothGatt.connect(adapterName);\n } catch (KuraException e) {\n logger.error(e.toString());\n }\n if (connected) {\n this.bluetoothGatt.setBluetoothLeNotificationListener(this);\n setFirmwareRevision();\n this.isConnected = true;\n return true;\n } else {\n // If connect command is not executed, close gatttool\n this.bluetoothGatt.disconnect();\n this.isConnected = false;\n return false;\n }\n}\n
A set of methods for reading from and writing to the internal register of the device are included in the class. The following code sample presents the methods to manage the temperature sensor.
/*\n* Enable temperature sensor\n*/\npublic void enableThermometer() {\n // Write \"01\" to enable thermometer sensor\n if (this.cc2650) {\n this.bluetoothGatt.writeCharacteristicValue(TiSensorTagGatt.HANDLE_TEMP_SENSOR_ENABLE_2650, \"01\");\n } else {\n this.bluetoothGatt.writeCharacteristicValue(TiSensorTagGatt.HANDLE_TEMP_SENSOR_ENABLE_2541, \"01\");\n }\n}\n\n/*\n* Disable temperature sensor\n*/\npublic void disableThermometer() {\n // Write \"00\" disable thermometer sensor\n if (this.cc2650) {\n this.bluetoothGatt.writeCharacteristicValue(TiSensorTagGatt.HANDLE_TEMP_SENSOR_ENABLE_2650, \"00\");\n } else {\n this.bluetoothGatt.writeCharacteristicValue(TiSensorTagGatt.HANDLE_TEMP_SENSOR_ENABLE_2541, \"00\");\n }\n}\n\n/*\n* Read temperature sensor\n*/\npublic double[] readTemperature() {\n double[] temperatures = new double[2];\n // Read value\n try {\n if (this.cc2650) {\n temperatures = calculateTemperature(\n this.bluetoothGatt.readCharacteristicValue(TiSensorTagGatt.HANDLE_TEMP_SENSOR_VALUE_2650));\n } else {\n temperatures = calculateTemperature(\n this.bluetoothGatt.readCharacteristicValue(TiSensorTagGatt.HANDLE_TEMP_SENSOR_VALUE_2541));\n }\n } catch (KuraException e) {\n logger.error(e.toString());\n }\n return temperatures;\n}\n\n/*\n* Read temperature sensor by UUID\n*/\npublic double[] readTemperatureByUuid() {\n double[] temperatures = new double[2];\n try {\n temperatures = calculateTemperature(\n this.bluetoothGatt.readCharacteristicValueByUuid(TiSensorTagGatt.UUID_TEMP_SENSOR_VALUE));\n } catch (KuraException e) {\n logger.error(e.toString());\n }\n return temperatures;\n}\n\n/*\n* Enable temperature notifications\n*/\npublic void enableTemperatureNotifications(TiSensorTagNotificationListener listener) {\n setListener(listener);\n // Write \"01:00 to enable notifications\n if (this.cc2650) {\n this.bluetoothGatt.writeCharacteristicValue(TiSensorTagGatt.HANDLE_TEMP_SENSOR_NOTIFICATION_2650,\n ENABLE_NOTIFICATIONS);\n } else {\n this.bluetoothGatt.writeCharacteristicValue(TiSensorTagGatt.HANDLE_TEMP_SENSOR_NOTIFICATION_2541,\n ENABLE_NOTIFICATIONS);\n }\n}\n\n/*\n* Disable temperature notifications\n*/\npublic void disableTemperatureNotifications() {\n unsetListener();\n // Write \"00:00 to enable notifications\n if (this.cc2650) {\n this.bluetoothGatt.writeCharacteristicValue(TiSensorTagGatt.HANDLE_TEMP_SENSOR_NOTIFICATION_2650,\n DISABLE_NOTIFICATIONS);\n } else {\n this.bluetoothGatt.writeCharacteristicValue(TiSensorTagGatt.HANDLE_TEMP_SENSOR_NOTIFICATION_2541,\n DISABLE_NOTIFICATIONS);\n }\n}\n\n/*\n * Set sampling period (only for CC2650)\n */\npublic void setThermometerPeriod(String period) {\n this.bluetoothGatt.writeCharacteristicValue(TiSensorTagGatt.HANDLE_TEMP_SENSOR_PERIOD_2650, period);\n}\n\n/*\n* Calculate temperature\n*/\nprivate double[] calculateTemperature(String value) {\n\n logger.info(\"Received temperature value: {}\", value);\n\n double[] temperatures = new double[2];\n\n byte[] valueByte = hexStringToByteArray(value.replace(\" \", \"\"));\n\n if (this.cc2650) {\n int ambT = shortUnsignedAtOffset(valueByte, 2);\n int objT = shortUnsignedAtOffset(valueByte, 0);\n temperatures[0] = (ambT >> 2) * 0.03125;\n temperatures[1] = (objT >> 2) * 0.03125;\n } else {\n\n int ambT = shortUnsignedAtOffset(valueByte, 2);\n int objT = shortSignedAtOffset(valueByte, 0);\n temperatures[0] = ambT / 128.0;\n\n double vobj2 = objT;\n vobj2 *= 0.00000015625;\n\n double tdie = ambT / 128.0 + 273.15;\n\n double s0 = 5.593E-14; // Calibration factor\n double a1 = 1.75E-3;\n double a2 = -1.678E-5;\n double b0 = -2.94E-5;\n double b1 = -5.7E-7;\n double b2 = 4.63E-9;\n double c2 = 13.4;\n double tref = 298.15;\n double s = s0 * (1 + a1 * (tdie - tref) + a2 * Math.pow(tdie - tref, 2));\n double vos = b0 + b1 * (tdie - tref) + b2 * Math.pow(tdie - tref, 2);\n double fObj = vobj2 - vos + c2 * Math.pow(vobj2 - vos, 2);\n double tObj = Math.pow(Math.pow(tdie, 4) + fObj / s, .25);\n\n temperatures[1] = tObj - 273.15;\n }\n\n return temperatures;\n}\n
The TiSensorTag class implements the org.eclipse.kura.bluetooth.BluetoothLeNotificationListener interface and the method onDataReceived is called when a BLE notification is received. In this example the notifications are used only for the buttons. The method is shown below.
public void onDataReceived(String handle, String value) {\n\n if (this.notificationListener != null) {\n Map<String, Object> values = new HashMap<>();\n if (handle.equals(TiSensorTagGatt.HANDLE_KEYS_STATUS_2541)\n || handle.equals(TiSensorTagGatt.HANDLE_KEYS_STATUS_2650)) {\n logger.info(\"Received keys value: {}\", value);\n if (!value.equals(\"00\")) {\n values.put(\"Keys\", Integer.parseInt(value));\n this.notificationListener.notify(this.device.getAdress(), values);\n }\n } else if (handle.equals(TiSensorTagGatt.HANDLE_TEMP_SENSOR_VALUE_2541)\n || handle.equals(TiSensorTagGatt.HANDLE_TEMP_SENSOR_VALUE_2650)) {\n double[] temperatures = calculateTemperature(value);\n values.put(\"Ambient\", temperatures[0]);\n values.put(\"Target\", temperatures[1]);\n this.notificationListener.notify(this.device.getAdress(), values);\n }\n }\n\n}\n
"},{"location":"java-application-development/how-to-use-legacy-bt-le/#deploy-and-validate-the-bundle","title":"Deploy and Validate the Bundle","text":"In order to proceed, you need to know the IP address of your embedded gateway that is on the remote target unit. Once you do, follow the mToolkit instructions for installing a single bundle to the remote target device located here. When the installation completes, the bundle starts automatically. You should see a message similar to the one below from /var/log/kura.log indicating that the bundle was successfully installed and configured, and started to search for TI SensorTags.
2015-11-11 13:38:19,208 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.t.BluetoothLe - Activating BluetoothLe example...\n2015-11-11 13:38:19,382 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.t.BluetoothLe - Bluetooth adapter interface => hci0\n2015-11-11 13:38:19,383 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.t.BluetoothLe - Bluetooth adapter address => 5C:F3:70:60:63:8F\n2015-11-11 13:38:19,383 [Component Resolve Thread (Bundle 6)] INFO o.e.k.e.b.t.BluetoothLe - Bluetooth adapter le enabled => true\n2015-11-11 13:38:19,395 [pool-26-thread-1] INFO o.e.k.e.b.t.BluetoothLe - startLeScan\n2015-11-11 13:38:19,396 [pool-26-thread-1] INFO o.e.k.l.b.l.BluetoothLeScanner - Starting bluetooth le scan...\n2015-11-11 13:38:19,406 [Component Resolve Thread (Bundle 6)] INFO o.e.k.c.c.ConfigurableComponentTracker - Adding ConfigurableComponent org.eclipse.kura.example.ble.tisensortag.BluetoothLe\n2015-11-11 13:38:19,408 [Component Resolve Thread (Bundle 6)] INFO o.e.k.c.c.ConfigurationServiceImpl - Registration of ConfigurableComponent org.eclipse.kura.example.ble.tisensortag.BluetoothLe by org.eclipse.kura.core.configuration.ConfigurationServiceImpl@19cb019...\n2015-11-11 13:38:19,424 [Component Resolve Thread (Bundle 6)] INFO o.e.k.c.c.ConfigurationServiceImpl - Registering org.eclipse.kura.example.ble.tisensortag.BluetoothLe with ocd: org.eclipse.kura.core.configuration.metatype.Tocd@106b1d9 ...\n2015-11-11 13:38:19,426 [Component Resolve Thread (Bundle 6)] INFO o.e.k.c.c.ConfigurationServiceImpl - Registration Completed for Component org.eclipse.kura.example.ble.tisensortag.BluetoothLe.\n2015-11-11 13:38:20,394 [pool-26-thread-1] INFO o.e.k.e.b.t.BluetoothLe - m_bluetoothAdapter.isScanning\n2015-11-11 13:38:21,394 [pool-26-thread-1] INFO o.e.k.e.b.t.BluetoothLe - m_bluetoothAdapter.isScanning\n2015-11-11 13:38:22,394 [pool-26-thread-1] INFO o.e.k.e.b.t.BluetoothLe - m_bluetoothAdapter.isScanning\n2015-11-11 13:38:23,394 [pool-26-thread-1] INFO o.e.k.e.b.t.BluetoothLe - m_bluetoothAdapter.isScanning\n2015-11-11 13:38:24,394 [pool-26-thread-1] INFO o.e.k.e.b.t.BluetoothLe - m_bluetoothAdapter.isScanning\n2015-11-11 13:38:25,394 [pool-26-thread-1] INFO o.e.k.e.b.t.BluetoothLe - m_bluetoothAdapter.isScanning\n2015-11-11 13:38:25,396 [pool-26-thread-1] INFO o.e.k.l.b.l.BluetoothLeScanner - Killing hcitool...\n2015-11-11 13:38:25,449 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - LE Scan ...\n2015-11-11 13:38:25,450 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - 7F:D8:F8:45:6B:C2 (unknown)\n2015-11-11 13:38:25,452 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - 7F:D8:F8:45:6B:C2 (unknown)\n2015-11-11 13:38:25,453 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - BC:6A:29:AE:CC:96 (unknown)\n2015-11-11 13:38:25,454 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - BC:6A:29:AE:CC:96 SensorTag\n2015-11-11 13:38:25,455 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - 68:64:4B:3F:04:9B (unknown)\n2015-11-11 13:38:25,456 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - 68:64:4B:3F:04:9B (unknown)\n2015-11-11 13:38:25,457 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - 18:EE:69:15:21:B0 (unknown)\n2015-11-11 13:38:25,458 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - 18:EE:69:15:21:B0 (unknown)\n2015-11-11 13:38:25,459 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - m_scanResult.add 68:64:4B:3F:04:9B - (unknown)\n2015-11-11 13:38:25,464 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - m_scanResult.add 18:EE:69:15:21:B0 - (unknown)\n2015-11-11 13:38:25,465 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - m_scanResult.add BC:6A:29:AE:CC:96 - SensorTag\n2015-11-11 13:38:25,466 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothLeScanner - m_scanResult.add 7F:D8:F8:45:6B:C2 - (unknown)\n2015-11-11 13:38:25,467 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Address 68:64:4B:3F:04:9B Name (unknown)\n2015-11-11 13:38:25,467 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Found device = 68:64:4B:3F:04:9B\n2015-11-11 13:38:25,468 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Address 18:EE:69:15:21:B0 Name (unknown)\n2015-11-11 13:38:25,468 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Found device = 18:EE:69:15:21:B0\n2015-11-11 13:38:25,469 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Address BC:6A:29:AE:CC:96 Name SensorTag\n2015-11-11 13:38:25,469 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - TI SensorTag BC:6A:29:AE:CC:96 found.\n2015-11-11 13:38:25,470 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Address 7F:D8:F8:45:6B:C2 Name (unknown)\n2015-11-11 13:38:25,470 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Found device = 7F:D8:F8:45:6B:C2\n2015-11-11 13:38:25,470 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Connecting to TiSensorTag...\n2015-11-11 13:38:25,475 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.l.b.l.BluetoothGattImpl - Sending connect message...\n2015-11-11 13:38:25,859 [DnsMonitorServiceImpl] WARN o.e.k.n.a.m.DnsMonitorServiceImpl - Not Setting DNS servers to empty\n2015-11-11 13:38:26,883 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.TiSensorTag - Received temperature value: 7f fe fc 0c\n2015-11-11 13:38:26,885 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Ambient: 25.96875 Target: 20.801530505264225\n2015-11-11 13:38:28,028 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.TiSensorTag - Received accelerometer value: ff 06 42\n2015-11-11 13:38:28,029 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Acc X: -0.015625 Acc Y: 0.09375 Acc Z: -1.03125\n2015-11-11 13:38:29,182 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.TiSensorTag - Received barometer value: e8 6a 22 56\n2015-11-11 13:38:29,183 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Humidity: 36.053864\n2015-11-11 13:38:30,327 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.TiSensorTag - Received magnetometer value: e5 f6 d6 fc 62 04\n2015-11-11 13:38:30,328 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Mag X: 203.43018 Mag Y: 320.43457 Mag Z: 765.7471\n2015-11-11 13:38:32,623 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.TiSensorTag - Received pressure value: 1d fd dd 99\n2015-11-11 13:38:32,625 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Pre : 99334.60900594086\n2015-11-11 13:38:33,767 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.TiSensorTag - Received gyro value: cc 01 1d ff d2 ff\n2015-11-11 13:38:33,769 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Gyro X: -101.55487 Gyro Y: -58.58612 Gyro Z: -87.898254\n2015-11-11 13:38:33,769 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.TiSensorTag - Not optical sensor on CC2541.\n2015-11-11 13:38:34,770 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.TiSensorTag - Not optical sensor on CC2541.\n2015-11-11 13:38:34,771 [BluetoothProcess Input Stream Gobbler] INFO o.e.k.e.b.t.BluetoothLe - Light: 0.0\n
"},{"location":"java-application-development/how-to-use-modbus/","title":"How to Use Modbus","text":"ModbusProtocolDevice is a service that provides a connection to a device or a network of devices over Serial Line (RS-232/RS-485) or Ethernet using the Modbus protocol. This service implements a subset of the Modbus Application Protocol as defined by Modbus Organization (for more information, refer to http://www.modbus.org/specs.php).
The ModbusProtocolDevice service needs to receive a valid Modbus configuration including the following parameters:
Modbus protocol mode - defines the protocol mode as RTU or ASCII (only RTU mode for Ethernet connections).
Timeout - sets the timeout in order to detect a disconnected device.
The ModbusProtocolDevice service also requires a valid Serial Line or Ethernet connection configuration including the following parameters:
parity
Ethernet
When a valid configuration is received, the ModbusProtocolDevice service tries to open the communication port. Serial Line communication uses the CommConnection class; Ethernet communication is based on java.net.Socket. When the communication is established, the client makes direct calls to the Modbus functions. The first parameter of each method is the Modbus address of the queried unit. This address must be in the range of 1 - 247.
"},{"location":"java-application-development/how-to-use-modbus/#function-codes","title":"Function Codes","text":"The following function codes are implemented within the ModbusProtocolDevice service:
01 (0x01) readCoils(int unitAddr,\u00a0 int dataAddress, int count) - read 1 to 2000 maximum contiguous status of coils from the attached field device with address \"unitAddr\". An array of booleans representing the requested data points is returned.
02 (0x02) readDiscreteInputs(int unitAddr,\u00a0 int dataAddress, int count) - read 1 to 2000 maximum contiguous status of discrete inputs from the attached field device with address \"unitAddr\". An array of booleans representing the requested data points is returned.
03 (0x03) readHoldingRegisters(int unitAddr,\u00a0 int dataAddress, int count) - read contents of 1 to 125 maximum contiguous block of holding registers from the attached field device with address \"unitAddr\". An array of int representing the requested data points (data registers on 2 bytes) is returned.
04 (0x04) readInputRegisters(int unitAddr,\u00a0 int dataAddress, int count) - read contents of 1 to 125 maximum contiguous block of input registers from the attached field device with address \"unitAddr\". An array of int representing the requested data points (data registers on 2 bytes) is returned.
05 (0x05) writeSingleCoil(int unitAddr,\u00a0 int dataAddress, boolean data) - write a single output to either ON or OFF in the attached field device with address \"unitAddr\".
06 (0x06) writeSingleRegister(int unitAddr,\u00a0 int dataAddress, int data) - write a single holding register in the attached field device with address \"unitAddr\".
15 (0x0F) writeMultipleCoils(int unitAddr,\u00a0 int dataAddress, boolean[ ] data) - write multiple coils in a sequence of coils to either ON or OFF in the attached field device with address \"unitAddr\".
16 (0x10) writeMultipleRegister(int unitAddr,\u00a0 int dataAddress, int[ ] data) - write a block of contiguous registers (1 to 123) in the attached field device with address \"unitAddr\".
All functions throw a ModbusProtocolException. Valid exceptions include:
INVALID_CONFIGURATION
NOT_AVAILABLE
NOT_CONNECTED
TRANSACTION_FAILURE
The ModbusProtocolDeviceService is an OSGi declarative service referenced in the client XML definition file:
<reference bind=\"setModbusProtocolDeviceService\"\n cardinality=\"1..1\"\n interface=\"org.eclipse.kura.protocol.modbus.ModbusProtocolDeviceService\"\n name=\"ModbusProtocolDeviceService\"\n policy=\"static\"\n unbind=\"unsetModbusProtocolDeviceService\"/>\n
public void setModbusProtocolDeviceService(ModbusProtocolDeviceService modbusService) {\n this.m_protocolDevice = modbusService;\n}\n\npublic void unsetModbusProtocolDeviceService(ModbusProtocolDeviceService modbusService) {\n this.m_protocolDevice = null;\n}\n
if(m_protocolDevice!=null){\n m_protocolDevice.disconnect();\n m_protocolDevice.configureConnection(modbusSerialProperties);\n}\n
If no exception occurs, the ModbusProtocolDevice can then be used to exchange data: boolean[] digitalInputs = m_protocolDevice.readDiscreteInputs(1, 2048, 8);\nint[] analogInputs = m_protocolDevice.readInputRegisters(1, 512, 8);\nboolean[] digitalOutputs = m_protocolDevice.readCoils(1, 2048, 6); // LEDS\n\n// to set LEDS\nm_protocolDevice.writeSingleCoil(1, 2047 + LED, On?TurnON:TurnOFF);\n
"},{"location":"java-application-development/how-to-use-new-beacon-apis/","title":"How to Use New Beacon APIs","text":""},{"location":"java-application-development/how-to-use-new-beacon-apis/#overview","title":"Overview","text":"Starting from version 3.1.0, Eclipse Kura implements a new set of APIs for managing Bluetooth Low Energy and Beacon devices. The new APIs replace the existing Bluetooth APIs, but the old ones are still available and can be used. So, the applications developed before Kura 3.1.0 continue to work.
The purpose of the new BLE Beacon APIs is to simplify the development of applications that interact with Bluetooth LE Beacon devices, offering clear and easy-to-use methods for advertising and scanning. Eclipse Kura offers out-of-the-box the implementation of the Beacon APIs for iBeacon\u2122 and Eddystone\u2122 technologies. Moreover, the new APIs allow to easily integrate new beacon implementations with Eclipse Kura.
"},{"location":"java-application-development/how-to-use-new-beacon-apis/#how-to-use-kura-ibeacontm-apis","title":"How to use Kura iBeacon\u2122 APIs","text":"This section briefly presents how to use the iBeacon\u2122 implementation of the Kura Beacon APIs, providing several code snippets to explain how to perform common operations on iBeacons. For a complete example on iBeacon advertising and scanning, please refer to the new iBeacon\u2122 advertiser and iBeacon\u2122 scanner examples. For more information about iBeacon\u2122 please refer to official page.
An application that wants to use the iBeacon\u2122 implementation of Kura Beacon APIs should bind the BluetoothLeService and BluetoothLeIBeaconService OSGI services, as shown in the following Java snippet:
public void setBluetoothLeService(BluetoothLeService bluetoothLeService) {\n this.bluetoothLeService = bluetoothLeService;\n}\n\npublic void unsetBluetoothLeService(BluetoothLeService bluetoothLeService) {\n this.bluetoothLeService = null;\n}\n\npublic void setBluetoothLeIBeaconService(BluetoothLeIBeaconService bluetoothLeIBeaconService) {\n this.bluetoothLeIBeaconService = bluetoothLeIBeaconService;\n}\n\npublic void unsetBluetoothLeIBeaconService(BluetoothLeIBeaconService bluetoothLeIBeaconService) {\n this.bluetoothLeIBeaconService = null;\n}\n
and in the component definition:
<reference bind=\"setBluetoothLeService\" \n cardinality=\"1..1\" \n interface=\"org.eclipse.kura.bluetooth.le.BluetoothLeService\" \n name=\"BluetoothLeService\" \n policy=\"static\" \n unbind=\"unsetBluetoothLeService\"/>\n\n<reference bind=\"setBluetoothLeIBeaconService\" \n cardinality=\"1..1\" \n interface=\"org.eclipse.kura.ble.ibeacon.BluetoothLeIBeaconService\" \n name=\"BluetoothLeIBeaconService\" \n policy=\"static\" \n unbind=\"unsetBluetoothLeIBeaconService\"/>\n
The BluetoothLeService is used to get the BluetoothLeAdapter to be used with the BluetoothLeIBeaconScanner and BluetoothLeIBeaconAdvertiser. As explained here, the adapter can be retrieved and powered on as follows:
this.bluetoothLeAdapter = this.bluetoothLeService.getAdapter(adapterName);\nif (this.bluetoothLeAdapter != null) {\n if (!this.bluetoothLeAdapter.isPowered()) {\n this.bluetoothLeAdapter.setPowered(true);\n }\n} \n
where adapterName is the name of the adapter, e.g. hci0.
"},{"location":"java-application-development/how-to-use-new-beacon-apis/#create-an-ibeacontm-advertiser","title":"Create an iBeacon\u2122 advertiser","text":"In order to properly configure an iBeacon\u2122 advertiser, a BluetoothLeIBeaconService is needed to create a new BluetoothLeIBeaconAdvertiser instance bound to a specific Bluetooth adapter:
try {\n BluetoothLeBeaconAdvertiser<BluetoothLeIBeacon> advertiser = this.bluetoothLeIBeaconService.newBeaconAdvertiser(this.bluetoothLeAdapter);\n} catch (KuraBluetoothBeaconAdvertiserNotAvailable e) {\n logger.error(\"Beacon Advertiser not available on {}\", this.bluetoothLeAdapter.getInterfaceName(),e);\n}\n
Then a BluetoothLeIBeacon object should be created, containing all the information to be broadcasted. In the following snippet, the BluetoothLeIBeacon object is instantiated and added to the advertiser. Then the broadcast time interval is set and the beacon advertising is started.
try {\n BluetoothLeIBeacon iBeacon = new BluetoothLeIBeacon(uuid, major, minor, txPower);\n advertiser.updateBeaconAdvertisingData(iBeacon);\n advertiser.updateBeaconAdvertisingInterval(minInterval, maxInterval;\n\n advertiser.startBeaconAdvertising();\n} catch (KuraBluetoothCommandException e) {\n logger.error(\"IBeacon configuration failed\", e);\n}\n
The BluetoothLeIBeacon represents the beacon packet that will be broadcasted by the advertiser and it should be configured will the following parameters:
Warning
Only one advertising packet can be broadcasted at a time on a specific Bluetooth adapter.
Finally, in the following snippet the advertiser is stopped and removed from the BluetoothLeIBeaconService:
try {\n advertiser.stopBeaconAdvertising();\n this.bluetoothLeIBeaconService.deleteBeaconAdvertiser(advertiser);\n} catch (KuraBluetoothCommandException e) {\n logger.error(\"Stop iBeacon advertising failed\", e);\n}\n
"},{"location":"java-application-development/how-to-use-new-beacon-apis/#create-an-ibeacontm-scanner","title":"Create an iBeacon\u2122 scanner","text":"As done for the advertiser, a BluetoothLeIBeaconService is needed to create a new BluetoothLeIBeaconScanner instance bound to a specific Bluetooth adapter:
bluetoothLeBeaconScanner<BluetoothLeIBeacon> scanner = this.bluetoothLeIBeaconService.newBeaconScanner(this.bluetoothLeAdapter);\n
A BluetoothLeIBeaconScanner needs a listener to collect the iBeacon packets that the Bluetooth adapter detects. In the following snippet, a simple listener that prints the iBeacon packet configuration is added to the scanner object:
private class iBeaconListener implements BluetoothLeBeaconListener<BluetoothLeIBeacon> {\n\n @Override\n public void onBeaconsReceived(BluetoothLeIBeacon beacon) {\n logger.info(\"iBeacon received from {}\", beacon.getAddress());\n logger.info(\"UUID : {}\", beacon.getUuid());\n logger.info(\"Major : {}\", beacon.getMajor());\n logger.info(\"Minor : {}\", beacon.getMinor());\n logger.info(\"TxPower : {}\", beacon.getTxPower());\n logger.info(\"RSSI : {}\", beacon.getRssi()); \n }\n\n}\n
scanner.addBeaconListener(listener);\n
The scanner is started for a specific time interval (in this case 10 seconds):
scanner.startBeaconScan(10);\n
Finally the scanner should be stopped, if needed, and the resources are released:
if (scanner.isScanning()) {\n scanner.stopBeaconScan();\n}\nscanner.removeBeaconListener(listener);\nthis.bluetoothLeIBeaconService.deleteBeaconScanner(scanner);\n
Note
The kura.legacy.bluetooth.beacon.scan property in the kura.properties file defines how the scan for beacons is performed. If set to true, the deprecated hcitool command is used. This guarantees that all the advertisement packets are reported. If set to false, the library will communicate to the OS using dbus. In the latter case, the rate of reports is limited and not all the advertisement packets are reported.
"},{"location":"java-application-development/how-to-use-new-beacon-apis/#how-to-use-kura-eddystonetm-apis","title":"How to use Kura Eddystone\u2122 APIs","text":"Eddystone\u2122 is a protocol specification that defines a BLE message format for proximity beacon messages. It describes several different frame types that may be used individually or in combinations to create beacons that can be used for a variety of applications. For more information please see here and here.
In this section the Eddystone\u2122 implementation of the Kura Beacon APIs is presented, providing several code snippets to explain how to perform common operations on them. For a complete example on Eddystone\u2122 advertising and scanning, please refer to the new Eddystone\u2122 advertiser and Eddystone\u2122 scanner examples.
Warning
Only Eddystone UID and URL frame types are currently supported.
As done with the iBeacon\u2122 implementation, an application has to bind the BluetoothLeService and BluetoothLeEddystoneService OSGI services, as shown in the following Java snippet:
public void setBluetoothLeService(BluetoothLeService bluetoothLeService) {\n this.bluetoothLeService = bluetoothLeService;\n}\n\npublic void unsetBluetoothLeService(BluetoothLeService bluetoothLeService) {\n this.bluetoothLeService = null;\n}\n\npublic void setBluetoothLeEddystoneService(BluetoothLeEddystoneService bluetoothLeEddystoneService) {\n this.bluetoothLeEddystoneService = bluetoothLeEddystoneService;\n}\n\npublic void unsetBluetoothLeEddystoneService(BluetoothLeEddystoneService bluetoothLeEddystoneService) {\n this.bluetoothLeEddystoneService = null;\n}\n
and in the component definition:
<reference bind=\"setBluetoothLeService\" \n cardinality=\"1..1\" \n interface=\"org.eclipse.kura.bluetooth.le.BluetoothLeService\" \n name=\"BluetoothLeService\" \n policy=\"static\" \n unbind=\"unsetBluetoothLeService\"/>\n\n<reference bind=\"setBluetoothLeEddystoneService\" \n cardinality=\"1..1\" \n interface=\"org.eclipse.kura.ble.eddystone.BluetoothLeEddystoneService\" \n name=\"BluetoothLeEddystoneService\" \n policy=\"static\" \n unbind=\"unsetBluetoothLeEddystoneService\"/>\n
The BluetoothLeService is used to get the BluetoothLeAdapter to be used with the BluetoothLeEddystoneScanner and BluetoothLeEddystoneAdvertiser. As explained here, the adapter can be retrieved and powered on as follows:
this.bluetoothLeAdapter = this.bluetoothLeService.getAdapter(adapterName);\nif (this.bluetoothLeAdapter != null) {\n if (!this.bluetoothLeAdapter.isPowered()) {\n this.bluetoothLeAdapter.setPowered(true);\n }\n} \n
where adapterName is the name of the adapter, e.g. hci0.
"},{"location":"java-application-development/how-to-use-new-beacon-apis/#create-an-eddystonetm-advertiser","title":"Create an Eddystone\u2122 advertiser","text":"In order to properly configure an Eddystone\u2122 advertiser, a BluetoothLeEddystoneService is needed to create a new BluetoothLeEddystoneAdvertiser instance bound to a specific Bluetooth adapter:
try {\n BluetoothLeBeaconAdvertiser<BluetoothLeEddystone> advertiser = this.advertising = this.bluetoothLeEddystoneService.newBeaconAdvertiser(this.bluetoothLeAdapter);\n} catch (KuraBluetoothBeaconAdvertiserNotAvailable e) {\n logger.error(\"Beacon Advertiser not available on {}\", this.bluetoothLeAdapter.getInterfaceName(),e);\n}\n
The advertiser has to be configured with a BluetoothLeEddystone object that contains all the information to be broadcasted. Currently, UID and URL frame types are supported. A UID frame can be created as follows:
BluetoothLeEddystone eddystone = new BluetoothLeEddystone();\neddystone.configureEddystoneUIDFrame(namespace, instance, txPower);\n
where namespace and instance are respectively 10-byte and 6-byte long sequences that compose a unique 16-byte Beacon ID. The txPower is the calibrated transmission power at 0 m.
A URL frame is created as follows:
BluetoothLeEddystone eddystone = new BluetoothLeEddystone();\neddystone.configureEddystoneURLFrame(url, txPower);\n
where url is the URL to be broadcasted and the txPower is the calibrated transmission power at 0 m.
After the BluetoothLeEddystone creation, the packet is added to the advertiser and the broadcast time interval is set. Then the advertiser is started:
try {\n advertiser.updateBeaconAdvertisingData(eddystone);\n advertiser.updateBeaconAdvertisingInterval(this.options.getMinInterval(), this.options.getMaxInterval());\n advertiserstartBeaconAdvertising();\n} catch (KuraBluetoothCommandException e) {\n logger.error(\"Eddystone configuration failed\", e);\n}\n
Finally, in the following snippet the advertiser is stopped and removed from the BluetoothLeEddystoneService:
try {\n advertiser.stopBeaconAdvertising();\n this.bluetoothLeEddystoneService.deleteBeaconAdvertiser(advertiser);\n} catch (KuraBluetoothCommandException e) {\n logger.error(\"Stop Advertiser advertising failed\", e);\n}\n
"},{"location":"java-application-development/how-to-use-new-beacon-apis/#create-an-eddystonetm-scanner","title":"Create an Eddystone\u2122 scanner","text":"As done for the advertiser, a BluetoothLeEddystoneService is needed to create a new BluetoothLeEddystoneScanner instance bound to a specific Bluetooth adapter:
bluetoothLeBeaconScanner<BluetoothLeEddystone> scanner = this.bluetoothLeEddystoneService.newBeaconScanner(this.bluetoothLeAdapter);\n
A BluetoothLeEddystoneScanner needs a listener to collect the Eddystone packets that the Bluetooth adapter detects. In the following snippet, a simple listener that detects the frame type and prints the packet content is added to the scanner object:
private class EddystoneListener implements BluetoothLeBeaconListener<BluetoothLeEddystone> {\n\n @Override\n public void onBeaconsReceived(BluetoothLeEddystone beacon) {\n logger.info(\"Eddystone {} received from {}\", eddystone.getFrameType(), eddystone.getAddress());\n if (\"UID\".equals(eddystone.getFrameType())) {\n logger.info(\"Namespace : {}\", bytesArrayToHexString(eddystone.getNamespace()));\n logger.info(\"Instance : {}\", bytesArrayToHexString(eddystone.getInstance()));\n } else if (\"URL\".equals(eddystone.getFrameType())) {\n logger.info(\"URL : {}\", eddystone.getUrlScheme() + eddystone.getUrl());\n }\n logger.info(\"TxPower : {}\", eddystone.getTxPower());\n logger.info(\"RSSI : {}\", eddystone.getRssi()); \n }\n\n}\n
scanner.addBeaconListener(listener);\n
The scanner is started for a specific time interval (in this case 10 seconds):
scanner.startBeaconScan(10);\n
Finally the scanner should be stopped, if needed, and the resources are released:
if (scanner.isScanning()) {\n scanner.stopBeaconScan();\n}\nscanner.removeBeaconListener(listener);\nthis.bluetoothLeEddystoneService.deleteBeaconScanner(scanner);\n
Note
The kura.legacy.bluetooth.beacon.scan property in the kura.properties file defines how the scan for beacons is performed. If set to true, the deprecated hcitool command is used. This guarantees that all the advertisement packets are reported. If set to false, the library will communicate to the OS using dbus. In the latter case, the rate of reports is limited and not all the advertisement packets are reported.
"},{"location":"java-application-development/how-to-use-new-beacon-apis/#add-new-beacon-apis-implementation","title":"Add new Beacon APIs implementation","text":"Eclipse Kura offers the implementation for iBeacon\u2122 and Eddystone\u2122 protocols, but it is possible to add implementations of different kinds of beacon protocols.
The org.eclipse.kura.bluetooth.le.beacon package contains the interfaces used by the beacon implementations:
The BluetoothLeBeaconManager, BluetoothLeBeaconScanner and BluetoothLeBeaconAdvertiser interfaces handles generic BluetoothLeBeacon objects and their implementations are provided by the org.eclipse.kura.ble.provider. The others interfaces, instead, are Beacon specific and their implementations depend on the specific protocol that is used. As a consequence, who wants to support a new Beacon protocol, should provide the implementation of the BluetoothLeBeaconService, BluetoothLeBeaconEncoder and BluetoothLeBeaconDecoder interfaces and extend the BluetoothLeBeacon class.
As an example, the org.eclipse.kura.ble.ibeacon.provider provides the implementation of the above APIs for the iBeacon\u2122 protocol. In this case, the org.eclipse.kura.ble.ibeacon package contains the following:
The org.eclipse.kura.internal.ble.ibeacon provides the implementations for the above interfaces:
The following image shows the UML diagram.
"},{"location":"java-application-development/how-to-use-new-bt-le-apis/","title":"How to Use New Bluetooth LE APIs","text":""},{"location":"java-application-development/how-to-use-new-bt-le-apis/#overview","title":"Overview","text":"Starting from version 3.1.0, Eclipse Kura implements a new set of APIs for managing Bluetooth Low Energy and Beacon devices. The new APIs replace the existing Bluetooth APIs, but the old ones are still available and can be used. So, the applications developed before Kura 3.1.0 continue to work.
The purpose of the new BLE APIs is to simplify the development of applications that interact with Bluetooth LE devices, offering clear and easy-to-use methods, and add new features to correctly manage the connection with remote devices. Moreover, the APIs organize the methods in a logical way to access all levels of a GATT client, from GATT services to GATT characteristics and descriptors, using UUIDs to identify the correct resource.
"},{"location":"java-application-development/how-to-use-new-bt-le-apis/#bluez-dbus-ble-gatt-api","title":"Bluez-Dbus - BLE GATT API","text":"The implementation of the new Kura BLE APIs is based on the Bluez-Dbus library that provides an easy to use Bluetooth LE API based on BlueZ over DBus. The library eases the access to GATT services and the management of BLE connections and discovery, without using any wrapper library as it is based on a newer version of dbus-java which uses jnr-unixsocket.
"},{"location":"java-application-development/how-to-use-new-bt-le-apis/#apis-description","title":"APIs description","text":"The new BLE APIs are exported in the org.eclipse.kura.bluetooth.le package. The interfaces are briefly described in the following.
More information about the APIs can be found in API Reference.
"},{"location":"java-application-development/how-to-use-new-bt-le-apis/#how-to-use-the-kura-ble-api","title":"How to use the Kura BLE API","text":"This section briefly presents how to use the Kura BLE APIs, providing several code snippets to explain how to perform common bluetooth operations. For a complete example, please refer to the new SensorTag application.
An application that wants to use the Kura BLE APIs should bind the BluetoothLeService OSGI service, as shown in the following Java snippet:
public void setBluetoothLeService(BluetoothLeService bluetoothLeService) {\n this.bluetoothLeService = bluetoothLeService;\n}\n\npublic void unsetBluetoothLeService(BluetoothLeService bluetoothLeService) {\n this.bluetoothLeService = null;\n}\n
and in the component definition:
<reference bind=\"setBluetoothLeService\" \n cardinality=\"1..1\" \n interface=\"org.eclipse.kura.bluetooth.le.BluetoothLeService\" \n name=\"BluetoothLeService\" \n policy=\"static\" \n unbind=\"unsetBluetoothLeService\"/>\n
"},{"location":"java-application-development/how-to-use-new-bt-le-apis/#get-the-bluetooth-adapter","title":"Get the Bluetooth adapter","text":"Once bound to the BluetoothLeService, an application can get the Bluetooth adapter and power on it, if needed:
this.bluetoothLeAdapter = this.bluetoothLeService.getAdapter(adapterName);\nif (this.bluetoothLeAdapter != null) {\n if (!this.bluetoothLeAdapter.isPowered()) {\n this.bluetoothLeAdapter.setPowered(true);\n }\n} \n
where adapterName is the name of the adapter, i.e. hci0.
"},{"location":"java-application-development/how-to-use-new-bt-le-apis/#search-for-ble-devices","title":"Search for BLE devices","text":"The BluetoothLeAdapter provides several methods to search for a device, a.k.a. perform a BLE discovery:
The following snippet shows how to perform a discovery of 10 seconds using findDevices method:
if (this.bluetoothLeAdapter.isDiscovering()) {\n try {\n this.bluetoothLeAdapter.stopDiscovery();\n } catch (KuraException e) {\n logger.error(\"Failed to stop discovery\", e);\n }\n}\nFuture<List<BluetoothLeDevice>> future = this.bluetoothLeAdapter.findDevices(10);\ntry {\n List<BluetoothLeDevice>; devices = future.get();\n} catch (InterruptedException | ExecutionException e) {\n logger.error(\"Scan for devices failed\", e);\n}\n
"},{"location":"java-application-development/how-to-use-new-bt-le-apis/#get-the-gatt-services-and-characteristics","title":"Get the GATT services and characteristics","text":"To get the GATT services using the BluetoothLeDevice, use the following snippet:
try {\n List<BluetoothLeGattService>; services = device.findServices();\n} catch (KuraBluetoothResourceNotFoundException e) {\n logger.error(\"Unable to find GATT services\", e);\n}\n
A specific GATT service can be retrieved using its UUID:
try {\n BluetoothLeGattService service = device.findService(uuid);\n} catch (KuraBluetoothResourceNotFoundException e) {\n logger.error(\"Unable to find GATT service\", e);\n}\n
Using the GATT service, it is possible to get a specific GATT characteristic (or the complete list) and the GATT descriptor from it:
try {\n BluetoothLeGattCharacteristic characteristic = service.findCharacteristic(characteristicUuid);\n BluetoothLeGattDescriptor descriptor = characteristic.findDescriptor(descriptorUuid);\n} catch (KuraBluetoothResourceNotFoundException e) {\n logger.error(\"Unable to find GATT resources\", e);\n}\n
"},{"location":"java-application-development/how-to-use-new-bt-le-apis/#io-operations-on-gatt-characteristics-and-descriptors","title":"IO operations on GATT characteristics and descriptors","text":"The Kura BLE APIs provides methods to manage the IO operations on GATT characteristics and descriptors. The following snippet provides an example on how to read and write data to a characteristic.
try {\n byte[] valueRead = characteristic.readValue();\n byte[] valueWrite = { 0x01};\n characteristic.writeValue(valueWrite);\n} catch (KuraBluetoothIOException e) {\n logger.error(\"IO operation failed\", e);\n}\n
In the following example, instead, a notification listener is configured to periodically receive the data from a GATT characteristic and print the first value of the given array. The period is internally set by the BLE device.
try {\n Consumer<byte[]>; callback = valueBytes -> System.out.println((int) valueBytes[0]);\n characteristic.enableValueNotifications(callback);\n} catch (KuraBluetoothNotificationException e) {\n logger.error();\n}\n
"},{"location":"java-application-development/how-to-use-new-bt-le-apis/#configure-bluez-on-the-raspberry-pi","title":"Configure Bluez on the Raspberry Pi","text":"The minimum version of Bluez supported by Kura Bluetooth LE APIs is 5.42. The Raspbian Stretch OS comes with Bluez 5.43, but older OS couldn't have an updated Bluez version. In this case, it is possible to compile and install Bluez from sources using a Raspberry Pi. The Bluez sources can be found here Proceed as follows:
sudo apt-get install libusb-dev libdbus-1-dev libglib2.0-dev libudev-dev libical-dev libreadline-dev\n
* Download bluez-5.43.tar.xz (or newer version) from here. * Decompress the compressed archive: tar -xf bluez-5.43.tar.x\n
cd bluez-5.43\n./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var --enable-library -disable-systemd --enable-experimental --enable-maintainer-mod\nmake\nmake install\n
"},{"location":"java-application-development/how-to-use-watchdog/","title":"How to use watchdog","text":""},{"location":"java-application-development/how-to-use-watchdog/#overview","title":"Overview","text":"When enabled, the watchdog is a peripheral monitor that will reboot the system if it is not refreshed during a certain time interval. In Kura, the WatchdogService can be used by critical applications. If the specified application is alive, the service notifies the watchdog; if the application is down, the service stops notifying the watchdog and a hardware reset occurs.
The WatchdogService notifies the kernel watchdog driver using the /dev/watchdog device file. You can verify that the watchdog driver is installed using the following command:
ls \u2013l /dev/watchdog\n
"},{"location":"java-application-development/how-to-use-watchdog/#configuration","title":"Configuration","text":"To configure the WatchdogService, select the WatchdogService option located in the Services area as shown in the screen capture below.
The WatchdogService provides the following configuration parameters:
enabled - sets whether or not this service is enabled or disabled. If enabled, you must set a pingInterval periodicity compatible with the watchdog driver.
pingInterval - specifies the time between two watchdog notifications. This time is hardware dependent. Generally, the maximum time between two notifications should be between 30 seconds and 1 minute. 10000 milliseconds for the pingInterval is typically a good choice.
The WatchdogService references a list of Critical Components that correspond to the applications implementing the CriticalComponent interface.
CriticalComponent is an interface that can be used to denote a component that is crucial to system operations. If a component implements CriticalComponent, then it must state its name as well as its criticalComponentTimeout. The name is a unique identifier in the system. The timeout is the length of time in milliseconds that the CriticalComponent must \"check in\" with the WatchdogService. If the CriticalComponent extends beyond the period of time specified in this timeout, a system reboot will be performed based on the WatchdogService configuration.
If at least one of the registered CriticalComponents has not \"checked in\" during the pingInterval time, the WatchdogService stops notifying the watchdog driver. The system reboots when the time interval reaches the hardware time that is programmed for the watchdog. When the WatchdogService is enabled and no application is using it, the service runs silently in the background.
An example of the WatchdogService can be found here.
The following code snippets demonstrate how to implement the CriticalComponent interface:
public class ModbusManager implements ConfigurableComponent, CriticalComponent, CloudClientListener\n
Registration of the class in WatchdogService::
if(m_watchdogService!=null){\n m_watchdogService.registerCriticalComponent(this);\n}\n
Periodic call to checkin method of WatchdogService in the main loop (keeps watchdog notification alive):
if(m_watchdogService!=null){\n m_watchdogService.checkin(this);\n}\n
"},{"location":"java-application-development/kura-workspace-setup/","title":"Kura Workspace Setup","text":"This document describes how to set up the Eclipse Kura workspace development environment, which consists of the following components:
This setup will allow you to develop applications or bundles running on Eclipse Kura. It will install only the APIs and the examples. If you want to contribute to the Eclipse Kura project follow this guide instead.
The Eclipse Kura development environment may be installed on Windows, Linux, or Mac OS. The setup instructions will be the same across each OS though each system may have unique characteristics.
Info
The local emulation of Eclipse Kura code is only supported in Linux and Mac, not in Windows.
"},{"location":"java-application-development/kura-workspace-setup/#jvm-installation","title":"JVM Installation","text":"Download and install JDK SE 8 from the following links as appropriate for your OS.
For Windows and Linux users, the JDK can be downloaded from the following link: Java SE 8 Downloads. Use the latest version of the Java SE Development Kit and download the version appropriate for your system.
For additional information regarding the installation of Java 8 on all supported operating systems, see JDK 8 and JRE 8 Installation Guide.
"},{"location":"java-application-development/kura-workspace-setup/#installing-eclipse-ide","title":"Installing Eclipse IDE","text":"Before installing Eclipse, you should choose directory locations for the Eclipse install and its workspaces.
Info
The following points should be kept in mind regarding Eclipse installs and workspaces:
Download the current distribution of Eclipse for your OS from Eclipse official website. Choose the Eclipse IDE for Eclipse Committers.
The zipped Eclipse file will be downloaded to the local file system and can be saved to a temporary location that can be deleted after Eclipse has been installed. After the file has been downloaded, it should be extracted to the Eclipse installs directory. The following screen capture shows the installation in Linux using an eclipse\\installs directory. The Eclipse executable will then be found in the eclipse\\installs\\eclipse directory. This installation will be different depending on the operating system.
Because there may potentially be future Eclipse installs extracted into this location, before doing anything else, rename the directory, such as eclipse\\installs\\juno1\\.
Warning
Once you begin using this Eclipse install, it should NOT be moved or renamed.
"},{"location":"java-application-development/kura-workspace-setup/#workspaces","title":"Workspaces","text":""},{"location":"java-application-development/kura-workspace-setup/#creating-an-eclipse-workspace","title":"Creating an Eclipse Workspace","text":"Run Eclipse by clicking its executable in the install directory.
When Eclipse is run for the first time, a workspace needs to be created. A single workspace will contain all the Java code/projects/bundles, Eclipse configuration parameters, and other relevant files for a specific business-level product. If the Use this as the default option is selected, the designated workspace becomes the default each time you run Eclipse.
If a workspace has not already been defined, or if you are creating a different workspace for another development project, enter a new workspace name. The workspace should be named appropriate to the project/product being developed.
Warning
Once you begin using a particular workspace, it should NOT be moved or renamed at any time.
Otherwise, select an existing workspace and click OK. After Eclipse is running, you can select the Eclipse menu File | Switch Workspace | Other to create or open a different workspace.
After the new workspace opens, click the Workbench icon to display the development environment.
Info
Additional workspace configuration:
lifecycle-mapping-metadata.xml
in Eclipse Kura workspace. You can find the file in the Windows -> Preferences -> Maven -> Lifecycle Mappings -> Open workspace lifecycle mappings metadata. After editing the file, reload it by pressing the \"Reload workspace lifecycle mappings metadata\" button. <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<lifecycleMappingMetadata>\n <lifecycleMappingFilters>\n <lifecycleMappingFilter>\n <symbolicName>org.eclipse.m2e.pde.connector</symbolicName>\n <versionRange>[2.1.2,)</versionRange>\n <packagingTypes>\n <packagingType>eclipse-test-plugin</packagingType>\n <packagingType>eclipse-plugin</packagingType>\n <packagingType>eclipse-feature</packagingType>\n </packagingTypes>\n </lifecycleMappingFilter>\n </lifecycleMappingFilters>\n</lifecycleMappingMetadata>\n
eclipse-tycho
plugin following this steps:Work with:
text field -> expand the category and select the Tycho Project Configurators Feature
and proceed with the installation.To set up your Eclipse Kura project workspace, you will need to download the Eclipse Kura User Workspace archive from Eclipse Kura Download Page.
From the Eclipse File menu, select the Import option. In the Import dialog box, expand the General heading, select Existing Projects into Workspace, and then click Next.
Now click the Select archive file option button and browse to the archive file, such as user_workspace_archive_.zip.
Finally, click Finish to import the projects. At this point, you should have four projects in your workspace. The four projects are as follows:
org.eclipse.kura.api \u2013 the core Eclipse Kura API.
org.eclipse.kura.demo.heater \u2013 an example project that you can use as a starting point for creating your own bundle.
org.eclipse.kura.emulator \u2013 the emulator project for running Eclipse Kura within Eclipse (Linux/Mac only).
target-definition \u2013 a set of required bundles that are dependencies of the APIs and Eclipse Kura.
Eclipse will also report some errors at this point. See the next section to resolve those errors.
"},{"location":"java-application-development/kura-workspace-setup/#workspace-setup","title":"Workspace Setup","text":"This section will guide the users to configure the development workspace environment.
"},{"location":"java-application-development/kura-workspace-setup/#jre-configuration","title":"JRE Configuration","text":"The latest Eclipse IDEs require and configure, by default, a Java 11 environment. In order to be able to leverage and develop using the new workspace for Eclipse Kura, the user will be required to perform a one-time operation to specify to the IDE a Java 8 JDK. Opening the Eclipse preferences and selecting the Installed JREs in the Java section, the user has to select an installed Java 8 instance.
After applying the configuration change, the user will be prompted to align also the compiler options. To do so, selecting the Compiler entry in the Java section, the user has to select 1.8 from the list of available Java versions.
After applying the changes, the user will be prompted to recompile the environment.
"},{"location":"java-application-development/kura-workspace-setup/#target-definition-setup","title":"Target Definition Setup","text":"Click the arrow next to the target-definition project in the workspace and double-click kura-equinox_.target to open it.
In the Target Definition window, click the link Set as Target Platform. Doing so will reset the target platform, rebuild the Eclipse Kura projects, and clear the errors that were reported. At this point, you are ready to begin developing Eclipse Kura-based applications for your target platform.
"},{"location":"java-application-development/kura-workspace-setup/#run-the-eclipse-kura-emulator","title":"Run the Eclipse Kura Emulator","text":"To start the Eclipse Kura emulator, select the \"Eclipse Kura Emulator.launch\" profile from \"Other Projects\" -> \"setups\" -> \"launchers\" and open it with \"Run as\" -> \"Run Configurations...\". Then click on the \"Arguments\" tab and update the \"VM arguments\" as follows to adapt the paths to the folder structure created by the Oomph installer:
-Dkura.have.net.admin=false -Dorg.osgi.framework.storage=/tmp/osgi/framework_storage -Dosgi.clean=true -Dosgi.noShutdown=true -Declipse.ignoreApp=true -Dorg.eclipse.kura.mode=emulator -Dkura.configuration=file:${workspace_loc}/../git/kura/kura/emulator/org.eclipse.kura.emulator/src/main/resources/kura.properties -Ddpa.configuration=/tmp/kura/dpa.properties -Dlog4j.configurationFile=file:${workspace_loc}/../git/kura/kura/emulator/org.eclipse.kura.emulator/src/main/resources/log4j.xml -Dkura.data=${workspace_loc}/kura/data -Dkura.snapshots=${workspace_loc}/kura/user/snapshots -Dorg.eclipse.equinox.http.jetty.customizer.class=org.eclipse.kura.jetty.customizer.KuraJettyCustomizer\n
The Eclipse Kura Web UI will be available at the following URL: http://127.0.0.1:8080 with username and password admin.
"},{"location":"java-application-development/ram-usage-considerations/","title":"RAM Usage Considerations","text":"During application development and before moving to production, it is advisable to understand if the amount of free RAM available on the device is enough for correct device operation.
Since RAM usage is application dependent, it is important to perform some stress tests to bring the device in the worst case conditions and verify system behavior.
Some of the aspects that should be taken into account are the following:
"},{"location":"java-application-development/ram-usage-considerations/#java-heap-memory-usage","title":"Java Heap memory usage","text":"Java heap is used to store the Java objects and classes at runtime.
The heap should be:
The size of the heap is controlled by the -Xms
and -Xmx
Java command line arguments. These parameters are defined in the /opt/eclipse/kura/bin/start_kura_debug.sh
(for development mode) and /opt/eclipse/kura/bin/start_kura_background.sh
(for production mode).
The -Xms
parameter defines the initial size of Java heap and -Xmx
defines the maximum size. The JVM will start using Xms
as the size of the heap, and then it will grow the heap at runtime up to Xmx
if needed, depending on application memory demand.
Resizing the heap has a cost in terms of performance, for this reason Xms
and Xmx
are set to the same size by default on most platforms.
In order to understand if the heap is large enough, it is advisable to perform a stress test simulating the conditions of maximum memory demand by the applications running inside Kura. For example, if a in-memory database instance is used by a DataService instance, during the test the database can be filled up to the maximum capacity to verify if this causes any issue.
Regarding point 2., it should be noted that heap memory is not necessarily backed by physical memory immediately after JVM startup. Even if the JVM performs an allocation of size Xmx
immediately, physical memory will be assigned to the Java process by the kernel only when the memory pages are actually accessed by the JVM.
For this reason the amount of physical memory used by the JVM might appear small right after system boot and grow with time, up to the maximum size. This can happen even if the applications running inside Kura do not have high memory requirements, and can lead to potential issues that show up only after some time.
In order to recreate such issues, the -XX:+AlwaysPreTouch
JVM command line option can be used during development to force the JVM to access all heap memory after start, causing the JVM process to use the maximum amount of physical memory immediately.
Another aspect that can lead to RAM related issues is logging. As a general rule, it is recommended to reduce the amount of log messages produced by Kura during normal operation.
Kura default logging configuration (/opt/eclipse/kura/log4j/log4j.xml
) depends on the platform.
The size of the files in the /var/log
directory will be checked periodically and the files will be rotated to the persisted /var/old_logs
directory if needed.
If external applications are installed on the system (e.g. Docker containers), their RAM usage should be analyzed as well.
Stress tests related to Java heap size, log size and external applications can be run simultaneously to simulate a worst case scenario.
"},{"location":"java-application-development/remote-debugging-on-target-platform/","title":"Remote debugging on target platform","text":"Eclipse Kura can be started with Java Debug Wire Protocol (JDWP) support, allowing the remote debugging of the developed application using Eclipse IDE. The procedure for remote debugging is presented in the following.
Connect to the target platform (i.e. RaspberryPi) and stop the Kura application typing sudo systemctl stop kura
or sudo /etc/init.d/kura stop
.
Start Kura with Java Debug Wire Protocol (JDWP) typing sudo /opt/eclipse/kura/bin/start_kura_debug.sh
. This will start Kura and open an OSGi console. It will also start listening for socket connections on port 8000.
Warning
Starting from Java 9, the JDWP socket connector accepts only local connections by default (see here for further details). To enable remote debugging on Java 9, the following line in /opt/eclipse/kura/bin/start_kura_debug.sh
: -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n \\has to be replaced with the following one: -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=*:8000,suspend=n \\
Open the tcp port 8000 in the firewall. This can be done through the firewall tab in Kura web interface or using iptables.
Install your application bundle on the target platform.
From Eclipse IDE, set a breakpoint in the application code at a point that will be reached (i.e. activation method, common logging statement, etc.). Then:
Click Debug
Eclipse will connect to the target platform VM and switch to the Debug Perspective when the breakpoint will have been hit.
To stop the remote debugging, select the \u201cDisconnect\u201d button from the Debug Perspective.
An Asset can be used inside a Wire Graph, in this case it is represented as node with two ports an input port and an output port. An Asset used in this way is called WireAsset.
"},{"location":"kura-wires/assets-as-wire-components/#read-mode","title":"Read mode","text":"Every time a WireAsset receives an envelope on its input port, it will read the values of all of its channels with READ
or READ_WRITE
type. The result is emitted as a WireEnvelope with a single WireRecord. The WireRecord contains the following properties:
assetName
, value type STRING and the emitting asset asset name as valueassetError
, value type STRING if emit.errors and emit.connection.errors is enabled and a general connection failure is returned by the Driver. See the description of the emit.connection.errors parameter for more details.assetTimestamp
, value type LONG, reporting a timestamp in milliseconds since Unix epoch (midnight, January 1, 1970 UTC). This property may be present or not depending on the value of the timestamp.mode configuration parameter or in case of general connection exception reported by the Driver, see the configuration parameter description for more details.For each channel in asset configuration with READ or READ_WRITE type named name:
<name>_timestamp
value type = LONG
reporting a timestamp in milliseconds since UNIX epoch. This property will be present only if the timestamp.mode Asset configuration property is set to PER_CHANNEL
<name>_error
, value type = STRING
reporting an error message. This property will be present only if read operation fails and the emit.errors Asset configuration property is set to true.For example, if an Asset that has the channel configuration shown in the picture below receives a WireEnvelope on its input port, it can emit an envelope with the following content, assuming that the read operation for each channel succeed:
modbusAsset
(type = STRING
)true
(type = BOOLEAN
)1597925188
(type = LONG
)false
(type = BOOLEAN
)1597925188
(type = LONG
)true
(type = BOOLEAN
)1597925188
(type = LONG
)false
(type = BOOLEAN
)1597925188
(type = LONG
)false
(type = BOOLEAN
)1597925188
(type = LONG
)true
(type = BOOLEAN
)1597925188
(type = LONG
)true
(type = BOOLEAN
)1597925188
(type = LONG
)false
(type = BOOLEAN
)1597925188
(type = LONG
)true
(type = BOOLEAN
)1597925188
(type = LONG
)123
(type = INTEGER
)1597925188
(type = LONG
)11
(type = INTEGER
)1597925188
(type = LONG
)false
(type = BOOLEAN
)1597925188
(type = LONG
)false
(type = BOOLEAN
)1597925188
(type = LONG
)The emitted WireEnvelope contains a single record containing the properties described above.
The Logger WireComponent can be used to inspect the messages emitted on a specific output port of a WireComponent by creating a connection between the output port of the component to the input port of the Logger. In this case the content of the received envelopes will be printed on device log (/var/log/kura.log
).
As mentioned above, the read operation is performed only if an envelope is received on the input port of the WireAsset. In order to achieve this, another component must be connected to the input port of the WireAsset.
An example of such component can be the Timer, this component can be configured to periodically emit an envelope containing a single wire record with a single property named TIMER reporting the current UNIX timestamp. Connecting this component to a WireAsset allows to implement a simple read polling cycle. The configuration of the timer defines the polling interval.
"},{"location":"kura-wires/assets-as-wire-components/#listen-mode","title":"Listen mode","text":"Enabling the listen flag allows to enable unsolicited notifications from the driver.
When this happens, the Asset will emit an WireEnvelope containing the updated value for the channel involved in the event. The content of this envelope is the same as the one generated in case of a read operation on the channel.
For example if listen is ticked for LED1 and the driver above detects a value change in that channel, the Asset will emit the following envelope:
modbusAsset
(type = STRING
)false
(type = BOOLEAN
)1597925200
(type = LONG
)This mode does not require to connect any component to the input port of the driver. The conditions that trigger the events for the channels and their meaning is reported in the Driver specific documentation.
Note: The example above is not completely realistic since the Modbus driver does not support listen mode. In this case ticking the listen flag will have no effect. The support for listen mode is mentioned in driver documentation.
Listen mode and Read mode are not mutually exclusive. If a channel is defined as READ
or READ_WRITE
and the listen flag is ticked, the driver will emit the channel value when a WireEnvelope is received on its input port or when a driver event is generated.
Additionally, the Wire Graph can also be used to update asset values through write operations, according to the following rule.
Every time a WireAsset receives an envelope on its input port, for each property contained in the received WireRecords with key <key>
, value type <value type>
and value <value>
, the driver will perform this operation: If a channel with name <key>
is defined in asset configuration whose value.type is equal to <value type>
and type is WRITE
or READ_WRITE
, then the Asset will write <value>
to the channel.
For example if the Asset above receives the following envelope:
false
(type = BOOLEAN
)78
(type = LONG
)true
(type = BOOLEAN
)bar
(type = STRING
)The following operations will happen:
BOOLEAN
, and type = READ_WRITE
, the driver will write false
to that channel for the rule mentioned above.78
property will have no effect, since the Asset configuration contains a channel named LED2 with type = READ_WRITE
, but value.type = BOOLEAN
!= LONG
.true
property will have no effect, since the asset contains a channel named Toggle-4
, with value.type = BOOLEAN
but type = READ
!= WRITE
| READ_WRITE
bar
property will have no effect, since none of the defined channels has foo
as name.READ
or READ_WRITE
, since a WireEnvelope has been received.The WireAsset component provides the following global (non per-channel) configuration parameters that can be used to customize component behavior:
emit.all.channels: Specifies whether the values of all READ or READ_WRITE channels should be emitted when a channel event is received in listen mode. If set to true, the values for all channels will be read and emitted, if set to false, only the value for the channel related to the event will be emitted.
timestamp.mode: Allows to configure how timestamps are emitted, the following modes are supported:
NO_TIMESTAMPS: no timestamp-related properties will be emitted.
PER_CHANNEL: the component will emit a driver-generated timestamp property per channel, as the value of the <channel name>_timestamp
property.
SINGLE_ASSET_GENERATED: the component will emit a single timestamp per request, generated by the Asset itself before emitting the envelope as the value of the assetTimestamp
property.
SINGLE_DRIVER_GENERATED_MAX and SINGLE_DRIVER_GENERATED_MIN: the component will emit a single driver generated timestamp being respectively the max (most recent) or min (oldest) among the timestamps of the channels as the value of the assetTimestamp
property.
emit.errors: Specifies whether channel specific errors should be included or not in emitted envelopes. If enabled, the component will add an additional property per channel, named <channel_name>_error
. If the channel operation fails, the property value will be an error message reported by the Driver, if the operation succeeds the property value will be the empty string.
emit.connection.errors: Specifies whether the component should emit an envelope in case of a general connection exception reported by the Driver (for example due to the fact that the connection with a remote device cannot be established). The error message associated with the exception will be emitted in a property named assetError
. In case of connection exception, channel values are not available and no channel related properties will be emitted. If the timestamp.mode property is set to a value other than NO_TIMESTAMPS, the component will also emit a assetTimestamp
property reporting current system time. This property will be ignored if emit.errors is disabled. Example of emitted envelope contents:
WireEnvelope
myAsset
(type = STRING
)Connection refused
(type = STRING
)1597925200
(type = LONG
)emit.on.change: If set to true, this component will include a channel value in the output emitted in Kura Wires only if it differs from the last emitted value for that channel. Channel errors will always be emitted if emit.errors is set to true
. If as a result of a read operation no changes are detected in any referenced channel, the Asset will emit an envelope containing no channel values, unless emit.empty.envelopes is set to false
.
emit.empty.envelopes: If set to false, this component will not emit empty envelopes.
The Wires feature aims to simplify the development of IoT Edge Computing Applications leveraging reusable configurable components that can be wired together and which, eventually, allows configurable cooperation between these components.
In the dataflow programming model, the application logic is expressed as a directed graph (flow) where each node can have inputs, outputs, and independent processing units. There are nodes that only produce outputs and ones that only consume inputs, which usually represent the start and the end of the flow. The inner-graph nodes process the inputs and produce outputs for downstream nodes. The processing unit of a node executes independently and does not affect the execution of other nodes. Thus, the nodes are highly reusable and portable.
In this way, the developer can easily prototype its solution without sacrificing flexibility and working at a high level of abstraction: the graph can be extended adding new nodes or drawing new connections. Furthermore, the developer can take advantage of the Eclipse Marketplace integration, being able to use open source or commercial building blocks into the final solution, by simply dragging and dropping a link to the Eclipse Marketplace in the Administrative Web UI.
"},{"location":"kura-wires/introduction/#data-model","title":"Data Model","text":"The communication over a single graph edge (Wire) is message oriented, messages are called WireEnvelopes. Each WireEnvelope contains a list of WireRecords. Each WireRecord contains a set of key-value pairs, called properties, the property key is always a string and it is unique within the same record, the property value can have one of the following types:
The Wire Composer is the main source of interaction with the Wires framework. It is accessible by clicking on the Wires button under System.
The Wires page is composed by a central composer, where the graph can be actually designed, a lower part that is populated when a wire component is clicked and that allows to update the component configuration and a section in the right with the available Wire Components.
"},{"location":"kura-wires/introduction/#wire-components","title":"Wire Components","text":"The following components are distributed with Kura:
In the top left part of the Wires page the Download button allows to download the configuration of the graph and of all the components that are part of the graph.
This snapshot can be used to replicate the same configuration across all the fleet of devices.
To upload the stored graph, the user has to access the Settings page and in the Snapshots section click the Upload and Apply button.
Warning
The graph configuration will be actually merged with the one existing. Be careful to Delete the existing graph and apply, if you don't want to merge with the existing Wires configuration.
"},{"location":"kura-wires/wire-graph-service-configuration-format/","title":"WireGraphService Configuration Format","text":"This document describes the configuration format for the WireGraphService component.
The WireGraphService configuration contains all the information related to the Wire Graph topology and rendering properties. The pid of the WireGraphService configuration is org.eclipse.kura.wire.graph.WireGraphService
.
The WireGraphService configuration represents the current graph layout as a single string typed property named WireGraph
that represents a serialized JSON representation of a WireGraph object.
An object representing a Wire Component position.
Properties:
number
number
{\n \"x\": 40,\n \"y\": 0\n}\n
{\n \"x\": 1.5\n}\n
{}\n
"},{"location":"kura-wires/wire-graph-service-configuration-format/#portnamelist","title":"PortNameList","text":"An object that specifies custom names for Wire Component input and output ports. The properties name for this object must be represented as an integer starting from 0, matching the index of the port whose name needs to be assigned. If the property name is not specified, the default port name will be used.
Properties:
string
The name for the port of index _portIndex{\n \"0\": \"foo\",\n \"1\": \"bar\"\n}\n
{}\n
"},{"location":"kura-wires/wire-graph-service-configuration-format/#renderingproperties","title":"RenderingProperties","text":"An object describing some Wire Component rendering parameters like position and custom port names.
Properties:
object
object
object
{\n \"inputPortNames\": {},\n \"outputPortNames\": {\n \"0\": \"foo\",\n \"1\": \"bar\"\n },\n \"position\": {\n \"x\": 40,\n \"y\": 0\n }\n}\n
{\n \"inputPortNames\": {},\n \"outputPortNames\": {\n \"0\": \"foo\",\n \"1\": \"bar\"\n }\n}\n
{\n \"position\": {\n \"x\": 40,\n \"y\": 0\n }\n}\n
{}\n
"},{"location":"kura-wires/wire-graph-service-configuration-format/#wirecomponent","title":"WireComponent","text":"An object that describes a Wire Component that is part of a Wire Graph
Properties:
string
The Wire Component pidnumber
An integer reporting the number of input ports of the Wire Component.number
An integer reporting the number of output ports of the Wire Component.object
{\n \"inputPortCount\": 1,\n \"outputPortCount\": 2,\n \"pid\": \"cond\",\n \"renderingProperties\": {\n \"inputPortNames\": {},\n \"outputPortNames\": {\n \"0\": \"foo\",\n \"1\": \"bar\"\n },\n \"position\": {\n \"x\": 40,\n \"y\": 0\n }\n }\n}\n
{\n \"inputPortCount\": 0,\n \"outputPortCount\": 1,\n \"pid\": \"timer\",\n \"renderingProperties\": {\n \"inputPortNames\": {},\n \"outputPortNames\": {},\n \"position\": {\n \"x\": -220,\n \"y\": -20\n }\n }\n}\n
"},{"location":"kura-wires/wire-graph-service-configuration-format/#wire","title":"Wire","text":"An object that describes a Wire connecting two Wire Components.
Properties:
string
The pid of the emitter component.number
The index of the output port of the emitter component that is connected to this Wire.string
The pid of the receiver component.number
The index of the input port of the receiver component that is connected to this Wire.{\n \"emitter\": \"timer\",\n \"emitterPort\": 0,\n \"receiver\": \"cond\",\n \"receiverPort\": 0\n}\n
"},{"location":"kura-wires/wire-graph-service-configuration-format/#wiregraph","title":"WireGraph","text":"An object that describes the topology and rendering properties of a Wire Graph
Properties:
array
The list of the wire components contained in the Wire Graphobject
array
The list of Wires contained in the Wire Graphobject
{\n \"components\": [\n {\n \"inputPortCount\": 0,\n \"outputPortCount\": 1,\n \"pid\": \"timer\",\n \"renderingProperties\": {\n \"inputPortNames\": {},\n \"outputPortNames\": {},\n \"position\": {\n \"x\": -220,\n \"y\": -20\n }\n }\n },\n {\n \"inputPortCount\": 1,\n \"outputPortCount\": 2,\n \"pid\": \"cond\",\n \"renderingProperties\": {\n \"inputPortNames\": {},\n \"outputPortNames\": {\n \"0\": \"foo\",\n \"1\": \"bar\"\n },\n \"position\": {\n \"x\": 40,\n \"y\": 0\n }\n }\n }\n ],\n \"wires\": [\n {\n \"emitter\": \"timer\",\n \"emitterPort\": 0,\n \"receiver\": \"cond\",\n \"receiverPort\": 0\n }\n ]\n}\n
"},{"location":"kura-wires/wire-service-references/","title":"References","text":"Additional information about Wires is available at the following resources:
"},{"location":"kura-wires/wire-service-references/#dzone","title":"DZONE","text":"The WIRE-V1 cloud request handler and the corresponding REST APIs allow to update, delete and get the current Wire Graph status. The request handler also supports creating, updating and deleting Asset and Driver instances and retrieving the metadata required for supporting Wire Graph editing applications.
The GET/graph/shapshot and PUT/graph/snapshot requests use the same format as the Wire Graph snapshot functionality of the Kura Web UI.
A Wire Graph snapshot can be obtained by navigating to the Wires section of Kura Web UI, clicking the Download button and selecting the JSON format.
Accessing the REST APIs requires to use an identity with the rest.wires.admin
permission assigned.
updateGraph
for the graph update operation, update:$pid
or delete:$pid
for update or delete operations performed on configurations not referenced by the Wire Graph, and snapshot
, for the snapshot creation operation. In case of an unexpected failure, a generic error response will be returned.response body :
Variants:
This request will replace the current graph topology with the received one. The received configuration must satisfy the following requirements. If any of the requirements is not met, the operation will fail and no changes will be applied to the system: * The configuration of the org.eclipse.kura.wire.graph.WireGraphService
component must be specified. * The configuration of the org.eclipse.kura.wire.graph.WireGraphService
component must contain a property named WireGraph
of STRING
type containing the graph layout as described in the WireGraphService document. * The inputPortCount
and outputPortCount
properties must be specified for all components in WireGraphService configuration. * The configuration of all components referenced by WireGraphService configuration that do not exist on target device must be specified. * The configuration of all components referenced by WireGraphService configuration that do not exist on target device must specify the service.factoryPid
configuration property reporting the component factory pid.
If a component already exists on the system and its configuration is supplied as part of the request, the component configuration will be updated. In this case the usual configuration merge semantics will be applied, the set of received properties will be merged with the existing one. The properties in the request body will overwrite the existing ones with the same name.
WireAsset configurations are treated sligtly differently, an update to a WireAsset configuration is performed by deleting the existing component and creating a new instance with the received configuration. This behavior is necessary in order to allow channel removal.
It is also allowed to specify Driver or Asset configurations that are not referenced by the Wire Graph included in the request body.
"},{"location":"kura-wires/wire-service-rest-v1/#delgraph","title":"DEL/graph","text":"delete:$pid
for delete operations, and snapshot
, for the snapshot creation operation. In case of an unexpected failure, a generic error response will be returned.response body :
Variants:
update:$pid
or delete:$pid
for update or delete operations, and snapshot
, for the snapshot creation operation. In case of an unexpected failure, a generic error response will be returned.response body :
Variants:
driverDescriptors
can be missing if no Driver instances exist on the system)wireComponentDefinitions
will be missing.wireComponentDefinitions
will be missing. If the metadata for a given factoryPid is not found, the request will succeed and it will not be included in the list.driverOCDs
will be missing.driverOCDs
will be missing. If the metadata for a given factoryPid is not found, the request will succeed and it will not be included in the list.driverChannelDescriptors
will be missing.driverChannelDescriptors
will be missing. If the metadata for a given pid is not found, the request will succeed and it will not be included in the list.A Wire Component definition object
Properties:
string
The component factory pidnumber
The minimum input port countnumber
The maximum number of input portsnumber
The default number of input portsnumber
The minimum number of output portsnumber
The maximum number of output portsnumber
The default number of output portsobject
object
array
object
{\n \"componentOCD\": [\n {\n \"cardinality\": 0,\n \"defaultValue\": \"50\",\n \"description\": \"The maximum number of envelopes that can be stored in the queue of this FIFO component\",\n \"id\": \"queue.capacity\",\n \"isRequired\": true,\n \"name\": \"queue.capacity\",\n \"type\": \"INTEGER\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"false\",\n \"description\": \"Defines the behavior in case of full queue: if set to true new envelopes will be dropped, otherwise, if an emitter delivers an envelope to this component it will block until the envelope can be successfully enqueued.\",\n \"id\": \"discard.envelopes\",\n \"isRequired\": true,\n \"name\": \"discard.envelopes\",\n \"type\": \"BOOLEAN\"\n }\n ],\n \"defaultInputPorts\": 1,\n \"defaultOutputPorts\": 1,\n \"factoryPid\": \"org.eclipse.kura.wire.Fifo\",\n \"maxInputPorts\": 1,\n \"maxOutputPorts\": 1,\n \"minInputPorts\": 1,\n \"minOutputPorts\": 1\n}\n
"},{"location":"kura-wires/wire-service-rest-v1/#driverchanneldescriptor","title":"DriverChannelDescriptor","text":"An object that describes Driver specific channel configuration properties
Properties:
string
The Driver pidstring
The Driver factory pidarray
object
{\n \"channelDescriptor\": [\n {\n \"cardinality\": 0,\n \"defaultValue\": \"AA:BB:CC:DD:EE:FF\",\n \"description\": \"sensortag.address\",\n \"id\": \"sensortag.address\",\n \"isRequired\": true,\n \"name\": \"sensortag.address\",\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"TEMP_AMBIENT\",\n \"description\": \"sensor.name\",\n \"id\": \"sensor.name\",\n \"isRequired\": true,\n \"name\": \"sensor.name\",\n \"option\": [\n {\n \"label\": \"TEMP_AMBIENT\",\n \"value\": \"TEMP_AMBIENT\"\n },\n {\n \"label\": \"TEMP_TARGET\",\n \"value\": \"TEMP_TARGET\"\n },\n {\n \"label\": \"HUMIDITY\",\n \"value\": \"HUMIDITY\"\n },\n {\n \"label\": \"ACCELERATION_X\",\n \"value\": \"ACCELERATION_X\"\n },\n {\n \"label\": \"ACCELERATION_Y\",\n \"value\": \"ACCELERATION_Y\"\n },\n {\n \"label\": \"ACCELERATION_Z\",\n \"value\": \"ACCELERATION_Z\"\n },\n {\n \"label\": \"MAGNETIC_X\",\n \"value\": \"MAGNETIC_X\"\n },\n {\n \"label\": \"MAGNETIC_Y\",\n \"value\": \"MAGNETIC_Y\"\n },\n {\n \"label\": \"MAGNETIC_Z\",\n \"value\": \"MAGNETIC_Z\"\n },\n {\n \"label\": \"GYROSCOPE_X\",\n \"value\": \"GYROSCOPE_X\"\n },\n {\n \"label\": \"GYROSCOPE_Y\",\n \"value\": \"GYROSCOPE_Y\"\n },\n {\n \"label\": \"GYROSCOPE_Z\",\n \"value\": \"GYROSCOPE_Z\"\n },\n {\n \"label\": \"LIGHT\",\n \"value\": \"LIGHT\"\n },\n {\n \"label\": \"PRESSURE\",\n \"value\": \"PRESSURE\"\n },\n {\n \"label\": \"GREEN_LED\",\n \"value\": \"GREEN_LED\"\n },\n {\n \"label\": \"RED_LED\",\n \"value\": \"RED_LED\"\n },\n {\n \"label\": \"BUZZER\",\n \"value\": \"BUZZER\"\n },\n {\n \"label\": \"KEYS\",\n \"value\": \"KEYS\"\n }\n ],\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"1000\",\n \"description\": \"notification.period\",\n \"id\": \"notification.period\",\n \"isRequired\": true,\n \"name\": \"notification.period\",\n \"type\": \"INTEGER\"\n }\n ],\n \"factoryPid\": \"org.eclipse.kura.driver.ble.sensortag\",\n \"pid\": \"sensortag\"\n}\n
"},{"location":"kura-wires/wire-service-rest-v1/#wiregraphmetadata","title":"WireGraphMetadata","text":"An object contiaining metatada describing Wire Components, Drivers and Assets
Properties:
array
object
array
object
array
object
array
object
{\n \"assetChannelDescriptor\": [\n {\n \"cardinality\": 0,\n \"defaultValue\": \"true\",\n \"description\": \"Determines if the channel is enabled or not\",\n \"id\": \"+enabled\",\n \"isRequired\": true,\n \"name\": \"enabled\",\n \"type\": \"BOOLEAN\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"Channel-1\",\n \"description\": \"Name of the Channel\",\n \"id\": \"+name\",\n \"isRequired\": true,\n \"name\": \"name\",\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"READ\",\n \"description\": \"Type of the channel\",\n \"id\": \"+type\",\n \"isRequired\": true,\n \"name\": \"type\",\n \"option\": [\n {\n \"label\": \"READ\",\n \"value\": \"READ\"\n },\n {\n \"label\": \"READ_WRITE\",\n \"value\": \"READ_WRITE\"\n },\n {\n \"label\": \"WRITE\",\n \"value\": \"WRITE\"\n }\n ],\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"INTEGER\",\n \"description\": \"Value type of the channel\",\n \"id\": \"+value.type\",\n \"isRequired\": true,\n \"name\": \"value.type\",\n \"option\": [\n {\n \"label\": \"BOOLEAN\",\n \"value\": \"BOOLEAN\"\n },\n {\n \"label\": \"BYTE_ARRAY\",\n \"value\": \"BYTE_ARRAY\"\n },\n {\n \"label\": \"DOUBLE\",\n \"value\": \"DOUBLE\"\n },\n {\n \"label\": \"INTEGER\",\n \"value\": \"INTEGER\"\n },\n {\n \"label\": \"LONG\",\n \"value\": \"LONG\"\n },\n {\n \"label\": \"FLOAT\",\n \"value\": \"FLOAT\"\n },\n {\n \"label\": \"STRING\",\n \"value\": \"STRING\"\n }\n ],\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"description\": \"Scale to be applied to the numeric value of the channel\",\n \"id\": \"+scale\",\n \"isRequired\": false,\n \"name\": \"scale\",\n \"type\": \"DOUBLE\"\n },\n {\n \"cardinality\": 0,\n \"description\": \"Offset to be applied to the numeric value of the channel\",\n \"id\": \"+offset\",\n \"isRequired\": false,\n \"name\": \"offset\",\n \"type\": \"DOUBLE\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"\",\n \"description\": \"Unit associated to the value of the channel\",\n \"id\": \"+unit\",\n \"isRequired\": false,\n \"name\": \"unit\",\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"false\",\n \"description\": \"Specifies if WireAsset should emit envelopes on Channel events\",\n \"id\": \"+listen\",\n \"isRequired\": true,\n \"name\": \"listen\",\n \"type\": \"BOOLEAN\"\n }\n ],\n \"driverChannelDescriptors\": [\n {\n \"channelDescriptor\": [\n {\n \"cardinality\": 0,\n \"defaultValue\": \"MyNode\",\n \"description\": \"node.id\",\n \"id\": \"node.id\",\n \"isRequired\": true,\n \"name\": \"node.id\",\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"2\",\n \"description\": \"node.namespace.index\",\n \"id\": \"node.namespace.index\",\n \"isRequired\": true,\n \"name\": \"node.namespace.index\",\n \"type\": \"INTEGER\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"DEFINED_BY_JAVA_TYPE\",\n \"description\": \"opcua.type\",\n \"id\": \"opcua.type\",\n \"isRequired\": true,\n \"name\": \"opcua.type\",\n \"option\": [\n {\n \"label\": \"DEFINED_BY_JAVA_TYPE\",\n \"value\": \"DEFINED_BY_JAVA_TYPE\"\n },\n {\n \"label\": \"BOOLEAN\",\n \"value\": \"BOOLEAN\"\n },\n {\n \"label\": \"SBYTE\",\n \"value\": \"SBYTE\"\n },\n {\n \"label\": \"INT16\",\n \"value\": \"INT16\"\n },\n {\n \"label\": \"INT32\",\n \"value\": \"INT32\"\n },\n {\n \"label\": \"INT64\",\n \"value\": \"INT64\"\n },\n {\n \"label\": \"BYTE\",\n \"value\": \"BYTE\"\n },\n {\n \"label\": \"UINT16\",\n \"value\": \"UINT16\"\n },\n {\n \"label\": \"UINT32\",\n \"value\": \"UINT32\"\n },\n {\n \"label\": \"UINT64\",\n \"value\": \"UINT64\"\n },\n {\n \"label\": \"FLOAT\",\n \"value\": \"FLOAT\"\n },\n {\n \"label\": \"DOUBLE\",\n \"value\": \"DOUBLE\"\n },\n {\n \"label\": \"STRING\",\n \"value\": \"STRING\"\n },\n {\n \"label\": \"BYTE_STRING\",\n \"value\": \"BYTE_STRING\"\n },\n {\n \"label\": \"BYTE_ARRAY\",\n \"value\": \"BYTE_ARRAY\"\n },\n {\n \"label\": \"SBYTE_ARRAY\",\n \"value\": \"SBYTE_ARRAY\"\n }\n ],\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"STRING\",\n \"description\": \"node.id.type\",\n \"id\": \"node.id.type\",\n \"isRequired\": true,\n \"name\": \"node.id.type\",\n \"option\": [\n {\n \"label\": \"NUMERIC\",\n \"value\": \"NUMERIC\"\n },\n {\n \"label\": \"STRING\",\n \"value\": \"STRING\"\n },\n {\n \"label\": \"GUID\",\n \"value\": \"GUID\"\n },\n {\n \"label\": \"OPAQUE\",\n \"value\": \"OPAQUE\"\n }\n ],\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"Value\",\n \"description\": \"attribute\",\n \"id\": \"attribute\",\n \"isRequired\": true,\n \"name\": \"attribute\",\n \"option\": [\n {\n \"label\": \"NodeId\",\n \"value\": \"NodeId\"\n },\n {\n \"label\": \"NodeClass\",\n \"value\": \"NodeClass\"\n },\n {\n \"label\": \"BrowseName\",\n \"value\": \"BrowseName\"\n },\n {\n \"label\": \"DisplayName\",\n \"value\": \"DisplayName\"\n },\n {\n \"label\": \"Description\",\n \"value\": \"Description\"\n },\n {\n \"label\": \"WriteMask\",\n \"value\": \"WriteMask\"\n },\n {\n \"label\": \"UserWriteMask\",\n \"value\": \"UserWriteMask\"\n },\n {\n \"label\": \"IsAbstract\",\n \"value\": \"IsAbstract\"\n },\n {\n \"label\": \"Symmetric\",\n \"value\": \"Symmetric\"\n },\n {\n \"label\": \"InverseName\",\n \"value\": \"InverseName\"\n },\n {\n \"label\": \"ContainsNoLoops\",\n \"value\": \"ContainsNoLoops\"\n },\n {\n \"label\": \"EventNotifier\",\n \"value\": \"EventNotifier\"\n },\n {\n \"label\": \"Value\",\n \"value\": \"Value\"\n },\n {\n \"label\": \"DataType\",\n \"value\": \"DataType\"\n },\n {\n \"label\": \"ValueRank\",\n \"value\": \"ValueRank\"\n },\n {\n \"label\": \"ArrayDimensions\",\n \"value\": \"ArrayDimensions\"\n },\n {\n \"label\": \"AccessLevel\",\n \"value\": \"AccessLevel\"\n },\n {\n \"label\": \"UserAccessLevel\",\n \"value\": \"UserAccessLevel\"\n },\n {\n \"label\": \"MinimumSamplingInterval\",\n \"value\": \"MinimumSamplingInterval\"\n },\n {\n \"label\": \"Historizing\",\n \"value\": \"Historizing\"\n },\n {\n \"label\": \"Executable\",\n \"value\": \"Executable\"\n },\n {\n \"label\": \"UserExecutable\",\n \"value\": \"UserExecutable\"\n }\n ],\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"1000\",\n \"description\": \"listen.sampling.interval\",\n \"id\": \"listen.sampling.interval\",\n \"isRequired\": true,\n \"name\": \"listen.sampling.interval\",\n \"type\": \"DOUBLE\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"10\",\n \"description\": \"listen.queue.size\",\n \"id\": \"listen.queue.size\",\n \"isRequired\": true,\n \"name\": \"listen.queue.size\",\n \"type\": \"LONG\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"true\",\n \"description\": \"listen.discard.oldest\",\n \"id\": \"listen.discard.oldest\",\n \"isRequired\": true,\n \"name\": \"listen.discard.oldest\",\n \"type\": \"BOOLEAN\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"false\",\n \"description\": \"listen.subscribe.to.children\",\n \"id\": \"listen.subscribe.to.children\",\n \"isRequired\": true,\n \"name\": \"listen.subscribe.to.children\",\n \"type\": \"BOOLEAN\"\n }\n ],\n \"factoryPid\": \"org.eclipse.kura.driver.opcua\",\n \"pid\": \"opcuaDriver\"\n }\n ],\n \"driverOCDs\": [\n {\n \"definition\": {\n \"ad\": [\n {\n \"cardinality\": 0,\n \"defaultValue\": \"default-server\",\n \"description\": \"OPC-UA Endpoint IP Address\",\n \"id\": \"endpoint.ip\",\n \"isRequired\": true,\n \"name\": \"Endpoint IP\",\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"53530\",\n \"description\": \"OPC-UA Endpoint Port\",\n \"id\": \"endpoint.port\",\n \"isRequired\": true,\n \"min\": \"1\",\n \"name\": \"Endpoint port\",\n \"type\": \"INTEGER\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"OPC-UA-Server\",\n \"description\": \"OPC-UA Server Name\",\n \"id\": \"server.name\",\n \"isRequired\": false,\n \"name\": \"Server Name\",\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"false\",\n \"description\": \"If set to true the driver will use the hostname, port, and server name parameters specified in the configuration instead of the values contained in endpoint descriptions fetched from the server.\",\n \"id\": \"force.endpoint.url\",\n \"isRequired\": false,\n \"name\": \"Force endpoint URL\",\n \"type\": \"BOOLEAN\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"120\",\n \"description\": \"Session timeout (in seconds)\",\n \"id\": \"session.timeout\",\n \"isRequired\": true,\n \"name\": \"Session timeout\",\n \"type\": \"INTEGER\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"60\",\n \"description\": \"Request timeout (in seconds)\",\n \"id\": \"request.timeout\",\n \"isRequired\": true,\n \"name\": \"Request timeout\",\n \"type\": \"INTEGER\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"40\",\n \"description\": \"The time to wait for the server response to the 'Hello' message (in seconds)\",\n \"id\": \"acknowledge.timeout\",\n \"isRequired\": true,\n \"name\": \"Acknowledge timeout\",\n \"type\": \"INTEGER\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"opc-ua client\",\n \"description\": \"OPC-UA application name\",\n \"id\": \"application.name\",\n \"isRequired\": true,\n \"name\": \"Application name\",\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"urn:kura:opcua:client\",\n \"description\": \"OPC-UA application uri\",\n \"id\": \"application.uri\",\n \"isRequired\": true,\n \"name\": \"Application URI\",\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"1000\",\n \"description\": \"The publish interval in milliseconds for the subscription created by the driver.\",\n \"id\": \"subscription.publish.interval\",\n \"isRequired\": true,\n \"name\": \"Subscription publish interval\",\n \"type\": \"LONG\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"PFX or JKS Keystore\",\n \"description\": \"Absolute path of the PKCS or JKS keystore that contains the OPC-UA client certificate, private key and trusted server certificates\",\n \"id\": \"certificate.location\",\n \"isRequired\": true,\n \"name\": \"Keystore path\",\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"0\",\n \"description\": \"Security Policy\",\n \"id\": \"security.policy\",\n \"isRequired\": true,\n \"name\": \"Security policy\",\n \"option\": [\n {\n \"label\": \"None\",\n \"value\": \"0\"\n },\n {\n \"label\": \"Basic128Rsa15\",\n \"value\": \"1\"\n },\n {\n \"label\": \"Basic256\",\n \"value\": \"2\"\n },\n {\n \"label\": \"Basic256Sha256\",\n \"value\": \"3\"\n }\n ],\n \"type\": \"INTEGER\"\n },\n {\n \"cardinality\": 0,\n \"description\": \"OPC-UA server username\",\n \"id\": \"username\",\n \"isRequired\": false,\n \"name\": \"Username\",\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"description\": \"OPC-UA server password\",\n \"id\": \"password\",\n \"isRequired\": false,\n \"name\": \"Password\",\n \"type\": \"PASSWORD\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"client-ai\",\n \"description\": \"Alias for the client certificate in the keystore\",\n \"id\": \"keystore.client.alias\",\n \"isRequired\": true,\n \"name\": \"Client certificate alias\",\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"false\",\n \"description\": \"Specifies whether to enable or not server certificate verification\",\n \"id\": \"authenticate.server\",\n \"isRequired\": true,\n \"name\": \"Enable server authentication\",\n \"type\": \"BOOLEAN\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"PKCS12\",\n \"description\": \"Keystore type\",\n \"id\": \"keystore.type\",\n \"isRequired\": true,\n \"name\": \"Keystore type\",\n \"option\": [\n {\n \"label\": \"PKCS11\",\n \"value\": \"PKCS11\"\n },\n {\n \"label\": \"PKCS12\",\n \"value\": \"PKCS12\"\n },\n {\n \"label\": \"JKS\",\n \"value\": \"JKS\"\n }\n ],\n \"type\": \"STRING\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"password\",\n \"description\": \"Configurable Property to set keystore password (default set to password)\",\n \"id\": \"keystore.password\",\n \"isRequired\": true,\n \"name\": \"Keystore password\",\n \"type\": \"PASSWORD\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"200\",\n \"description\": \"Maximum number of items that will be included in a single request to the server.\",\n \"id\": \"max.request.items\",\n \"isRequired\": true,\n \"name\": \"Max request items\",\n \"type\": \"INTEGER\"\n },\n {\n \"cardinality\": 0,\n \"defaultValue\": \"BROWSE_PATH\",\n \"description\": \"The format to be used for channel name for subtree subscriptions. If set to BROWSE_PATH, the channel name will contain the browse path of the source node relative to the subscription root. If set to NODE_ID, the name will contain the node id of the source node.\",\n \"id\": \"subtree.subscription.name.format\",\n \"isRequired\": true,\n \"name\": \"Subtree subscription events channel name format\",\n \"option\": [\n {\n \"label\": \"BROWSE_PATH\",\n \"value\": \"BROWSE_PATH\"\n },\n {\n \"label\": \"NODE_ID\",\n \"value\": \"NODE_ID\"\n }\n ],\n \"type\": \"STRING\"\n }\n ],\n \"description\": \"OPC-UA Driver\",\n \"id\": \"org.eclipse.kura.driver.opcua\",\n \"name\": \"OpcUaDriver\"\n },\n \"pid\": \"org.eclipse.kura.driver.opcua\"\n }\n ],\n \"wireComponentDefinitions\": [\n {\n \"componentOCD\": [\n {\n \"cardinality\": 0,\n \"defaultValue\": \"records[0].TIMER !== null && records[0].TIMER.getValue() > 10 && records[0]['TIMER'].getValue() < 30;\\n\",\n \"description\": \"The boolean expression to be evaluated by this component when a wire envelope is received.\",\n \"id\": \"condition\",\n \"isRequired\": true,\n \"name\": \"condition\",\n \"type\": \"STRING\"\n }\n ],\n \"defaultInputPorts\": 1,\n \"defaultOutputPorts\": 2,\n \"factoryPid\": \"org.eclipse.kura.wire.Conditional\",\n \"inputPortNames\": {\n \"0\": \"if\"\n },\n \"maxInputPorts\": 1,\n \"maxOutputPorts\": 2,\n \"minInputPorts\": 1,\n \"minOutputPorts\": 2,\n \"outputPortNames\": {\n \"0\": \"then\",\n \"1\": \"else\"\n }\n }\n ]\n}\n
"},{"location":"kura-wires/wire-service-rest-v1/#wire-graph-snapshot-example","title":"Wire Graph snapshot example","text":"{\n \"configs\": [\n {\n \"pid\": \"org.eclipse.kura.wire.graph.WireGraphService\",\n \"properties\": {\n \"WireGraph\": {\n \"type\": \"STRING\",\n \"value\": \"{\\\"components\\\":[{\\\"pid\\\":\\\"timer\\\",\\\"inputPortCount\\\":0,\\\"outputPortCount\\\":1,\\\"renderingProperties\\\":{\\\"position\\\":{\\\"x\\\":-300,\\\"y\\\":-20},\\\"inputPortNames\\\":{},\\\"outputPortNames\\\":{}}},{\\\"pid\\\":\\\"logger\\\",\\\"inputPortCount\\\":1,\\\"outputPortCount\\\":0,\\\"renderingProperties\\\":{\\\"position\\\":{\\\"x\\\":-100,\\\"y\\\":-20},\\\"inputPortNames\\\":{},\\\"outputPortNames\\\":{}}}],\\\"wires\\\":[{\\\"emitter\\\":\\\"timer\\\",\\\"emitterPort\\\":0,\\\"receiver\\\":\\\"logger\\\",\\\"receiverPort\\\":0}]}\"\n }\n }\n },\n {\n \"pid\": \"timer\",\n \"properties\": {\n \"componentDescription\": {\n \"type\": \"STRING\",\n \"value\": \"A wire component that fires a ticking event on every configured interval\"\n },\n \"componentId\": {\n \"type\": \"STRING\",\n \"value\": \"timer\"\n },\n \"componentName\": {\n \"type\": \"STRING\",\n \"value\": \"Timer\"\n },\n \"cron.interval\": {\n \"type\": \"STRING\",\n \"value\": \"0/10 * * * * ?\"\n },\n \"emitter.port.count\": {\n \"type\": \"INTEGER\",\n \"value\": 1\n },\n \"factoryComponent\": {\n \"type\": \"BOOLEAN\",\n \"value\": false\n },\n \"factoryPid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.wire.Timer\"\n },\n \"kura.service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"timer\"\n },\n \"receiver.port.count\": {\n \"type\": \"INTEGER\",\n \"value\": 0\n },\n \"service.factoryPid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.wire.Timer\"\n },\n \"service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.wire.Timer-1642493602000-13\"\n },\n \"simple.custom.first.tick.interval\": {\n \"type\": \"INTEGER\",\n \"value\": 0\n },\n \"simple.first.tick.policy\": {\n \"type\": \"STRING\",\n \"value\": \"DEFAULT\"\n },\n \"simple.interval\": {\n \"type\": \"INTEGER\",\n \"value\": 10\n },\n \"simple.time.unit\": {\n \"type\": \"STRING\",\n \"value\": \"SECONDS\"\n },\n \"type\": {\n \"type\": \"STRING\",\n \"value\": \"SIMPLE\"\n }\n }\n },\n {\n \"pid\": \"logger\",\n \"properties\": {\n \"componentDescription\": {\n \"type\": \"STRING\",\n \"value\": \"A wire component which logs data as received from upstream connected Wire Components\"\n },\n \"componentId\": {\n \"type\": \"STRING\",\n \"value\": \"logger\"\n },\n \"componentName\": {\n \"type\": \"STRING\",\n \"value\": \"Logger\"\n },\n \"emitter.port.count\": {\n \"type\": \"INTEGER\",\n \"value\": 0\n },\n \"factoryComponent\": {\n \"type\": \"BOOLEAN\",\n \"value\": false\n },\n \"factoryPid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.wire.Logger\"\n },\n \"kura.service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"logger\"\n },\n \"log.verbosity\": {\n \"type\": \"STRING\",\n \"value\": \"QUIET\"\n },\n \"receiver.port.count\": {\n \"type\": \"INTEGER\",\n \"value\": 1\n },\n \"service.factoryPid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.wire.Logger\"\n },\n \"service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.wire.Logger-1642493602046-14\"\n }\n }\n }\n ]\n}\n
"},{"location":"kura-wires/wires-mqtt-namespace/","title":"Wires MQTT Namespace","text":"The CloudPublisher is a WireComponent that converts a WireEnvelope in a KuraPayload and publishes it over MQTT. Each WireRecord in a WireEnvelope is trivially converted to a KuraPayload and published on a configurable semantic data or control topic. During this process, the emitter PID of the WireEnvelope is discarded.
The CloudPublisher is agnostic with respect to the contents of the WireEnvelope. It does not know for example if a WireEnvelope contains data readings emitted from a WireAsset. On the other hand, WireAssetS are first-class citizens of a Wire graph and the source of the information which is processed by the downstream Wire components. Eventually, the WireEnvelope representing the output of the processing is connected to a CloudPublisher and published to a Cloud platform.
In the simplest case, a WireAsset is directly connected to a CloudPublisher and it would be useful to publish the telemetry data under a well-known topic namespace, for example the following full topic:
<accountName>/<deviceID>/W1/A1/<assetName>\n
In this case ${assetName} matches the emitterPID of the WireEnvelope emitted by the WireAsset and received by a CloudPublisher.
Interested applications can then subscribe to (or query a message datastore for):
<accountName>/<deviceID>/W1/#
for all Wires (W) topics<accountName>/<deviceID>/W1/A1/#
for all WireAsset (W/A) topics<accountName>/<deviceID>/W1/A1/<assetName>
for all topics for a specific WireAssetIn a more complex scenario there might be filters between the WireAsset \u201csource\u201d and the CloudPublisher \u201csink\u201d and the emitterPID of the WireEnvelope received by the publisher no longer matches the emitterPID of the WireEnvelope emitted by the WireAsset. However the published data still represents \u201cAsset\u201d (filtered) data and should be published under the topic above.
The Kura Wires model haven\u2019t the notion of source of an WireEnvelope since a given WireEnvelope instance does not move across the graph but only from one WireEmitter to downstream WireReceiverS that are free to emit something semantically different.
To overcome this issue:
W1/A1/$assetName
where tokens prefixed with $
will be expanded to the value of a property with the same name in a WireEnvelope\u2019s WireRecord.assetName
property to the WireEnvelope\u2019s WireRecord.The Join Component is a Multiport-enabled component that merges into a single Wire Envelope the properties contained in the envelopes received in the input ports. It is provided by default in every Kura installation.
In the image above a simple usage example of the Join component: two timers simulate separate paths in the graph and the envelopes received by the Conditional component are then merged into a single Wire Envelope that is then received by the logger component.
The behaviour of the Join component is specified by the barrier property.
"},{"location":"kura-wires/multiport-wire-components/mathematical-components-example/","title":"Mathematical Components Example","text":"Mathematical Wire components can be installed from the Eclipse Marketplace. For these examples, the Wire Math Multiport Components DP will be used, but other more specific operators can be found on the marketplace (like trigonometric functions).
The following Multiport-enabled Mathematical examples are provided:
In order to allow a better routing of data through the Wire Graph, Kura introduces a new class of Wire components named Multiport Wire Components.
With the addition of this new functionality, a compatible component instance can be defined with an arbitrary number of input and output ports.
In the example provided, we have two components in the Wire Composer:
Those components are available in every default installation of Kura.
In order to show the potentialities of the new APIs, in the Eclipse Kura Marketplace and in the Kura downloads page, are available few more multiport-enabled components for Mathematical processing.
"},{"location":"kura-wires/multiport-wire-components/multiport-wire-components/#convert-a-component-to-a-multiport-component","title":"Convert a Component to a Multiport Component","text":""},{"location":"kura-wires/multiport-wire-components/multiport-wire-components/#component-configuration-changes","title":"Component Configuration Changes","text":"The following properties need to be specified in the component configuration:
The component should also provide service interface org.eclipse.kura.wire.WireComponent
"},{"location":"kura-wires/multiport-wire-components/multiport-wire-components/#code-changes","title":"Code Changes","text":"To leverage all the new Multiport functionalities, a Multiport-enabled component must use the newly introduced MultiportWireSupport APIs that provide support to get the list of Emitter and Receiver Ports, as well as to create a new Wire Envelope from a list of Wire Records.
For the conditional component, that has two output ports, the following code allows to get the proper Wire Support from the Wire Helper Service and to get the then and else ports to be used to push the processed envelopes.
this.wireSupport = (MultiportWireSupport) this.wireHelperService.newWireSupport(this);\n final List<EmitterPort> emitterPorts = this.wireSupport.getEmitterPorts();\n this.thenPort = emitterPorts.get(0);\n this.elsePort = emitterPorts.get(1);\n
To emit the result, the code has to be adapted to use the Wire Support to create the Wire Envelope that has to be sent. Effectively, the envelope is sent to the corresponding wire invoking the emit method of the corresponding Port, as shown below.
final WireEnvelope outputEnvelope = this.wireSupport.createWireEnvelope(inputRecords);\n\nif ((Boolean) decision) {\n this.thenPort.emit(outputEnvelope);\n} else {\n this.elsePort.emit(outputEnvelope);\n}\n
"},{"location":"kura-wires/script-components/graalvm-conditional-component/","title":"GraalVM\u2122 Conditional Component","text":"The Conditional Component is a multiport-enabled component that implements the if-then-else logic in the Wire Composer.
In the image above a simple usage example of the conditional component: a timer ticks and the envelope is received by the conditional component. If the timer has an even number of seconds, then it will evaluate to true
and forward the received envelope to the then port: the 'verbose' logger will receive the input.
The choice between the two ports is performed based on a condition expressed in the component configuration as in the image below.
"},{"location":"kura-wires/script-components/graalvm-filter-component/","title":"GraalVM\u2122 Filter Component","text":"The Filter Component provides scripting functionalities in Kura Wires using the GraalVM\u2122 JavaScript engine:
The following global variables are available to the script:
input
: an object that represents the received wire envelope.output
: an object that allows to emit wire records.logger
: a slf4j logger.The following utility functions are available (see Creating and emitting wire records for usage):
newWireRecord(Map<String, TypedValue<?>) -> WireRecord
newByteArray(int) -> byte[]
newBooleanValue(boolean) -> TypedValue
newByteArrayValue(byte[]) -> TypedValue
newDoubleValue(number) -> TypedValue
newIntegerValue(number) -> TypedValue
newLongValue(number) -> TypedValue
newStringValue(object) -> TypedValue
The following global constants expose the org.eclipse.kura.type.DataType
enum variants:
BOOLEAN
BYTE_ARRAY
DOUBLE
FLOAT
INTEGER
LONG
STRING
The received envelope is represented by the input global variable and is mapped in Javascript as a WireEnvelope
object.
GraalVM Javascript Engine allows a 1:1 mapping of Java Objects to JavaScript ones. Hence, it is possible to access the WireRecord
s of the envelope and the emitter pid using the methods specified in the WireEnvelope
Kura API:
logger.info('Emitter pid is {}', input.getEmitterPid())\nvar records = input.getRecords()\n
The records
array can be iterated to extract the WireRecord
properties (reference the WireRecord
Kura API):
for(let i=0; i<records.length; i++) {\n // WireRecord.getProperties() returns a map of String - TypedValue\n for (const [keyString, typedValue] of records[i].getProperties()) {\n logger.info('The {}-th record contains:'\\, String(i))\n logger.info('{}={}\\n', keyString, typedValue.getValue())\n }\n}\n
As in the example above, wireRecord.getProperties
returns a map of String, TypedValue
. Refer to the TypedValue
Kura API for the accessible public methods list.
New mutable WireRecord
instances can be created using the newWireRecord(Map<String, TypedValue<?>)
function. The properties of a mutable WireRecord
can be modified by setting Javascript object properties. The properties of a WireRecord
object must be instances of the TypedValue
class created using the new<type>Value()
family of functions. Setting different kind of objects as properties of a WireRecord
will result in an exception.
The output global variable is an object that can be used for emitting WireRecord
s. This object contains a list of WireRecord
s that will be emitted when the script execution finishes if no exceptions are thrown. The following code is an example of how to emit a list containing a single WireRecord
:
var output = new Array()\nvar outputMap = new Object()\n\nvar byteArray = newByteArray(4)\nbyteArray[0] = 1\nbyteArray[1] = 2\nbyteArray[2] = 0xaa\nbyteArray[3] = 0xbb\n\noutputMap['example.integer'] = newIntegerValue(10)\noutputMap['example.long'] = newLongValue(100)\noutputMap['example.float'] = newFloatValue(1.014)\noutputMap['example.double'] = newDoubleValue(10.12)\noutputMap['example.boolean'] = newBooleanValue(true)\noutputMap['example.string'] = newStringValue('Hello World!')\noutputMap['example.byte.array'] = newByteArrayValue(byteArray)\n\noutput[0] = newWireRecord(outputMap)\n
"},{"location":"kura-wires/script-components/graalvm-filter-component/#script-context","title":"Script context","text":"The script.context.drop option allows to reset the script context. If set to true
the script context will be dropped every time the component configuration is updated, resetting the value of any persisted variable.
In the example below, with script.context.drop=false the following script will preserve the value of counter
across executions. Setting script.context.drop=true will cause counter
to be undefined
every time the component is triggered.
counter = typeof(counter) === 'undefined'\n ? 0 // counter is undefined, initialise it to zero\n : counter; // counter is already defined, keep the previous value\n
"},{"location":"kura-wires/script-components/introduction/","title":"Introduction to the Script Components","text":"The Script Components allow for performing more complex operations on the received Wire Envelopes using a JavaScript Engine.
Depending if the target device is running on Java 8 or Java 17, there are several components to choose from.
For devices running a JRE with Nashorn JS Engine (Java < 15), a Script Filter and a Conditional Component are provided:
The above components will run only on Java < 15 since the Nashorn dependency is not included in the DP. The two components are available in the Eclipse Marketplace as two separate entries. These components are deprecated as of Kura version 5.3.
The following components instead have the GraalVM\u2122 JavaScript Engine included in the DP and therefore do not require a JRE with Nashorn JS Engine:
The input scripts for these components are not compatible with the Nashorn implementations Script Filter and Conditional Component. Both components are shipped as a single DP named org.eclipse.kura.wire.script.tools. Since the JS engine dependency is shipped along with the DP, these components will work on both Java 8 and Java 17 devices but the DP is bigger in size (~18,6 MB).
"},{"location":"kura-wires/script-components/nashorn-conditional-component/","title":"Nashorn Conditional Component","text":"Warning
This component is deprecated as of Kura version 5.3 since no more available on Java 17.
The Conditional component is a multiport-enabled component that implements the if-then-else logic in the Wire Composer. It is provided by default in every Kura installation.
In the image above a simple usage example of the Conditional component: a timer ticks and the envelope is received by the Conditional component. The message is then processed and can be sent downstream to the logger component (then port) or to a publisher (else port).
The choice between the two ports is performed based on a condition expressed in the Conditional component configuration.
"},{"location":"kura-wires/script-components/nashorn-script-filter/","title":"Nashorn Script Filter","text":"Warning
This component is deprecated as of Kura version 5.3 since no more available on Java 17.
The Script Filter Component provides scripting functionalities in Kura Wires using the Nashorn Javascript engine:
The following global variables are available to the script:
input
: an object that represents the received wire envelope.output
: an object that allows to emit wire records.logger
: a slf4j loggerThe following utility functions are available (see Creating and emitting wire records for usage):
newWireRecord(void) -> WireRecordWrapper
newByteArray(void) -> byte[]
newBooleanValue(boolean) -> TypedValue
newByteArrayValue(byte[])
-> TypedValue
newDoubleValue(number) -> TypedValue
newFloatValue(number) -> TypedValue
newIntegerValue(number) -> TypedValue
newLongValue(number) -> TypedValue
newStringValue(object) -> TypedValue
The following global constants expose the org.eclipse.kura.type.DataType
enum variants:
BOOLEAN
BYTE_ARRAY
DOUBLE
FLOAT
INTEGER
LONG
STRING
The received envelope is represented by the input global variable and it has the following properties:
Each element of the records array is an immutable object that represents a received wire record. Wire record properties are directly mapped to Javascript object properties, and are instances of the org.eclipse.kura.type.TypedValue
class. Each Wire Record property has the following methods available:
getType(void) -> DataType
: Returns the type of the value, as a DataType enum variant. Can be matched against the data type constants described above.getValue(void) -> Object
: Returns the actual value.The javascript objects referred as WireRecords in this guide are not instances of the org.eclipse.kura.wire.WireRecord
class, but are wrappers that map WireRecord properties into javascript properties. The following code is a simple example script that show how to use the filter:
// get the first record from the envelope\nvar record = input.records[0]\n// let's assume it contains the LED boolean property and the TEMPERATURE double property\nrecord.LED1.getType() === BOOLEAN // evaluates to true\nif (record.LED1.getValue()) {\n // LED1 is on\n}\nrecord.LED1.getType() === DOUBLE // evaluates to true\nif (record.TEMPERATURE.getValue() > 50) {\n // temperature is high, do something\n}\n
"},{"location":"kura-wires/script-components/nashorn-script-filter/#creating-and-emitting-wire-records","title":"Creating and emitting wire records","text":"New mutable WireRecord
instances can be created using the newWireRecord(void) -> WireRecordWrapper
function. The properties of a mutable WireRecord
can be modified by setting Javascript object properties. The properties of a WireRecord
object must be instances of the TypedValue
class created using the new<type>Value()
family of functions. Setting different kind of objects as properties of a WireRecord
will result in an exception.
The output global variable is an object that can be used for emitting WireRecords. This object contains a list of WireRecords that will be emitted when the script execution finishes, if no exceptions are thrown. New records can be added to the list using the add(WireRecordWrapper)
function. It is also possible to emit records contained in the received WireEnvelope.
The script filter will emit a wire envelope only if the WireRecord list is not empty when the script execution completes. The following code is an example about how to emit a value:
var record = newWireRecord()\n\nvar byteArray = newByteArray()\nbyteArray[0] = 1\nbyteArray[1] = 2\nbyteArray[2] = 0xaa\nbyteArray[3] = 0xbb\n\nrecord.LED1 = newBooleanValue(true)\nrecord.foo = newStringValue('bar')\nrecord['myprop'] = newDoubleValue(123.456)\nrecord['example.long'] = newLongValue(100)\nrecord['example.float'] = newFloatValue(1.014)\nrecord['example.byte.array'] = newByteArrayValue(byteArray)\n\noutput.add(record)\n
"},{"location":"kura-wires/script-components/nashorn-script-filter/#script-context","title":"Script context","text":"The script.context.drop option allows to reset the script context. If set to true
the script context will be dropped every time the component configuration is updated, resetting the value of any persisted variable.
In the example below, with script.context.drop=false the following script will preserve the value of counter
across executions. Setting script.context.drop=true will cause counter
to be undefined
every time the component is triggered.
counter = typeof(counter) === 'undefined'\n ? 0 // counter is undefined, initialise it to zero\n : counter; // counter is already defined, keep the previous value\n
"},{"location":"kura-wires/single-port-wire-components/ai-wire-component/","title":"AI Wire Component","text":"The component allows interacting with an InferenceEngineService
to perform machine learning-related operations. For boards that are not explicitly made for AI, the component can be installed from the Eclipse Marketplace at this link.
An InferenceEngineService is a Kura service that implements a simple API to interface with an Inference Engine. The Inference Engine allows to perform inference on trained Artificial Intelligence models commonly described by a file and some configuration for explaining its input and outputs. An example of Inference Engine implementation is the Nvidia\u2122 Triton Server inference engine.
In a normal machine learning flow, the input is preprocessed before it is given to the machine learning algorithm, and the result is processed again to be adapted to the rest of the pipeline.
Once these models are loaded in the engine, the AI wire component allows to specify the name of the models that are used in the pre-processing, infer, and post-processing steps. Only the infer model name is mandatory so that it is possible to just use the strictly necessary steps in case the pre/post-processing is performed directly by the infer step.
"},{"location":"kura-wires/single-port-wire-components/ai-wire-component/#models-input-and-output-formats","title":"Models Input and Output formats","text":"The AI wire component takes a WireEnvelope
as an input, it processes its records and feeds them to the specified preprocessing or inference model. The outputs of the inference or the post-processing step are then reconverted into a wire record. This section explains the inputs and output formats that the wire component is expecting. Not specifying the models according to this contract will result in a non-functioning inference.
The 3 inference steps are applied on each WireRecord
contained in the input WireEnvelope
.
The inputs and outputs will have assigned the corresponding Kura DataType
, which can be one of:
BOOLEAN
DOUBLE
FLOAT
INTEGER
LONG
STRING
BYTE_ARRAY
Reference to Introduction for the data types that are allowed to flow through the wires.
The models that manage the input and the output must expect a list of inputs such that:
WireRecord
properties[1]
In the following, two example configurations for Triton Inference Engine models are provided. A complete usage example that implements an Anomaly Detector using a RaspberryPi SenseHat is provided in the Kura examples repository.
"},{"location":"kura-wires/single-port-wire-components/ai-wire-component/#input-specification-example","title":"Input Specification Example","text":"Following, an example of a model configuration for the Nvidia\u2122 Triton Inference Engine. It expects the input from the WireEnvelope
that contains a record with properties:
ACCELERATION
of type Float
CHANNEL_0
of type Integer
STREAM
of type byte[]
GYRO
of type Boolean
This record can be generated from an asset with channel names as above. The output will be a single tensor of type Float
, of shape 1x13, and name OUT_PRE
.
Note that each input will have shape 1.
name: \"preprocessor\"\nbackend: \"python\"\n\ninput [\n {\n name: \"ACCELERATION\"\n data_type: FP32\n dims: [ 1 ]\n }\n]\ninput [\n {\n name: \"CHANNEL_0\"\n data_type: INT32\n dims: [ 1 ]\n }\n]\ninput [\n {\n name: \"STREAM\"\n data_type: BYTES\n dims: [ 1 ]\n }\n]\ninput [\n {\n name: \"GYRO\"\n data_type: BOOL\n dims: [ 1 ]\n }\n]\noutput [\n {\n name: \"OUT_PRE\"\n data_type: FP32\n dims: [ 13 ]\n }\n]\ninstance_group [{ kind: KIND_CPU }]\n
"},{"location":"kura-wires/single-port-wire-components/ai-wire-component/#output-specification-example","title":"Output Specification Example","text":"Following, an example of a Nvidia\u2122 Triton Inference Engine configuration that takes input IN_POST
and produces outputs that will be mapped to a WireRecord
with the properties as follows: - RESULT0
of type Boolean
- RESULT1
of type Integer
- RESULT2
of type byte[]
- RESULT3
of type Float
Note that each output will have shape 1.
name: \"postprocessor\"\nbackend: \"python\"\n\ninput [\n {\n name: \"IN_POST\"\n data_type: FP32\n dims: [ 1, 5 ]\n }\n]\noutput [\n {\n name: \"RESULT0\"\n data_type: BOOL\n dims: [ 1 ]\n }\n]\noutput [\n {\n name: \"RESULT1\"\n data_type: INT32\n dims: [ 1 ]\n }\n]\noutput [\n {\n name: \"RESULT2\"\n data_type: BYTES\n dims: [ 1 ]\n }\n]\noutput [\n {\n name: \"RESULT3\"\n data_type: FP32\n dims: [ 1 ]\n }\n]\ninstance_group [{ kind: KIND_CPU }]\n
"},{"location":"kura-wires/single-port-wire-components/db-store-and-filter/","title":"Wire Record Store and Wire Record Query","text":"This tutorial will present how to use Wire Record Store and Wire Record Query components and provide an example based on the OPC-UA simulated server already used in OPC-UA Application.
The Wire Record Store component allows the wire graphs to interact with a persistend Wire Record store implementation, for example a SQL database. It stores in a user-defined collection all the envelopes received by the component.
The Wire Record Query component, instead, can run a custom query on the attached store and emit the result on the wire.
Note
The Wire Record Store and Wire Record Query components have been introduced in Kura 5.3.0 as a replacement of the Db Store and Db Filter, that have been deprecated.
The reason of the deprecation is the fact that Db Store and Db Filter only support databases that provide a JDBC interface. Moreover, the old Db Store interacts with the database using a set of hardcoded SQL queries. This fact makes it difficult to use it with different databases since the syntax of the queries is usually database-specific.
The new components use the org.eclipse.kura.wire.store.provider.WireRecordStoreProvider
and org.eclipse.kura.wire.store.provider.QueryableWireRecordStoreProvider
APIs introduced in 5.3.0 allowing to use them with generic data store implementations.
Please note that Wire Record Query component is not portable by nature, since it allows to execute an arbitrary user defined query. The new APIs allows to use it with non-JDBC data stores.
The Wire Record Store component can be configured as follows:
The Wire Record Query component can be configured as follows:
The following procedure will create a wire graph that collects data from a simulated OPC-UA Server, stores it in a table in the database, using the Wire Record Store component, and publishes it in the cloud platform. Moreover, the Wire Record Query component is used to read from the database and write data to the OPC-UA Server based on the values read.
"},{"location":"kura-wires/single-port-wire-components/db-store-and-filter/#configure-opc-ua-server-simulator","title":"Configure OPC-UA server simulator","text":"Configure the new service as follows:
Click on Wires under System
Configure the new OPC-UA asset, adding new Channels as shown in the following image. Make sure that all the channels are set to READ.
Add a new Wire Record Store named DBStore component and configure it as follows:
Add another Asset with the OPC-UA Driver, configured as shown in the following image. Be sure that all the channels are set to WRITE.
Note
Be aware that the Query syntax can vary accordingly to the dialect used by the database. For example, the MySQL dialect doesn't allow to surround the table or columns names with double-quotes. In the H2DB, this is mandatory instead.
Connect the components as shown in the following image, then click on \u201cApply\u201d and check the logs and the cloud platform that the data is correctly published.
This page describes the usage of the FIFO component in Wires.
The current Wires threading model allows any component to perform potentially blocking operations when a wire envelope is received.
The fact that the wire envelopes are delivered synchronously implies that if a wire component performs blocking operations, other components in the same subgraph might be blocked as well, introducing delays in the processing of the graph.
The FIFO component can be used for decoupling blocking or slow wire components from other parts of the graph that cannot tolerate delays.
In the graph above, the NODELAY component cannot tolerate potential delays introduced by the DB component, adding a FIFO component allows to decouple the two components.
This component implements a FIFO queue that operates as follows:
In this way, the threads running the upstream components are not affected by blocking operations performed by the downstream components.
In the example above there will be two threads that manage the processing of the graph:
A thread from the TIMER Quartz scheduler pool handles the processing for the NODELAY component and submits the envelopes produced by it to the queue of the FIFO component.
A second thread introduced by the FIFO component pops the received envelopes from the queue and dispatches them to the DB component, performing the processing required by it.
In this way, the NODELAY and DB components are decoupled because they are managed by different threads.
"},{"location":"kura-wires/single-port-wire-components/fifo-component/#configuration","title":"Configuration","text":"The FIFO component configuration is composed of the following properties:
queue.capacity: The size of the queue in terms of the number of storable wire envelopes.
discard.envelopes : Configures the behavior of the component in case of a full queue.
If set to true, envelopes received when the queue is full will be dropped. In this mode, submitting an envelope to the queue is always a non-blocking operation. It should be used if occasionally losing wire envelopes is acceptable for the application, but introducing delays for upstream components is not.
If set to false, adding an envelope when the queue is full will block the submitting thread until there is space in the queue. Submitting an envelope to the FIFO component can be a blocking operation if the queue is full. This mode should be used if dropping wire envelopes is unacceptable for upstream components.
The probability of dropping envelopes in discard.envelopes=true mode or the probability of blocking upstream components in discard.envelopes=false mode can be controlled by setting a proper queue size.
"},{"location":"kura-wires/usage-examples/eddystone-driver-application/","title":"Eddystone\u2122 Driver Application with RuuviTag+","text":"As presented in Eddystone Driver, Kura provides a specific driver that can be used to listen for Eddystone\u2122 beacons. The driver is available only for gateways that support the new Kura BLE APIs.
This tutorial will explain how to configure an Eddystone\u2122 driver and put it into a Wire graph that retrieves data from a RuuviTag+. For further information about RuuviTag see here.
"},{"location":"kura-wires/usage-examples/eddystone-driver-application/#configure-kura-wires-eddystone-application","title":"Configure Kura Wires Eddystone application","text":"Install the Eddystone\u2122 driver from the Eclipse Kura Marketplace.
On the Kura Web Interface, instantiate an Eddystone\u2122 Driver:
From the Drivers and Assets tab, add a new asset bound to the Eddystone\u2122 driver:
UID
type and the second for the URL
. In this example only the URL
will be used.Click on Wires under System.
Add a new Asset with the previously added Eddystone asset.
Add a new Javascript Filter component. The filter will be configured to parse the URL
frames coming from the RuuviTag+ and extract the environmental data from the on-board sensors. In the script window write the following code:
function toHexString(str) {\n var hex = '';\n for ( i = 0; i < str.length; i++ ) {\n var hexTemp = str.charCodeAt(i).toString(16)\n hex += (hexTemp.length==2?hexTemp:'0'+hexTemp);\n}\nreturn hex;\n};\n\nfunction decodeValues(rawSensors) {\n var rawSensorsDecoded = Base64.decode(rawSensors)\n logger.info(toHexString(rawSensorsDecoded))\n var sensorsValues = new Array();\n // Data Format Definition (4)\n var format = parseInt(rawSensorsDecoded[0].charCodeAt(0));\n if (format == 4) {\n sensorsValues.push(format)\n // Humidity\n sensorsValues.push(rawSensorsDecoded[1].charCodeAt(0) * 0.5)\n // Temperature\n sensorsValues.push(rawSensorsDecoded[2].charCodeAt(0) & 0x7f)\n // Pressure\n sensorsValues.push(parseInt(rawSensorsDecoded[4].charCodeAt(0) << 8 )+ parseInt(rawSensorsDecoded[5].charCodeAt(0) & 0xff) + 50000)\n // Random id of tag\n sensorsValues.push(rawSensorsDecoded[6].charCodeAt(0))\n }\n return sensorsValues;\n};\n\nload(\"https://gist.githubusercontent.com/jarus/948005/raw/524bea3b4e0b74c06c9cfd2a8e54429dda1918fe/base64.js\")\nvar record = input.records[0]\nif (record.URLEddystone != null) {\n var values = record.URLEddystone.getValue().split(\";\")\n\n if (values.length == 5 && values[1].split(\"#\").length == 2) {\n var outRecord = newWireRecord()\n var sensorsValues = decodeValues(values[1].split(\"#\")[1])\n if (sensorsValues.length == 5) {\n outRecord.format = newIntegerValue(sensorsValues[0])\n outRecord.humidity = newDoubleValue(sensorsValues[1])\n outRecord.temperature = newDoubleValue(sensorsValues[2])\n outRecord.pressure = newIntegerValue(sensorsValues[3])\n outRecord.id = newIntegerValue(sensorsValues[4])\n }\n outRecord.txPower = newIntegerValue(parseInt(values[2]))\n outRecord.rssi = newIntegerValue(parseInt(values[3]))\n outRecord.distance = newDoubleValue(parseFloat(values[4]))\n\n output.add(outRecord)\n }\n}\n
Add Logger component and set the log.verbosity to VERBOSE.
Connect the Asset to the Filter and this to the Logger.
Click on Apply and check on the logs that the environmental data are correctly logged.
INFO o.e.k.w.s.f.p.ScriptFilter - 04541a00c35078\nINFO o.e.k.i.w.l.Logger - Received WireEnvelope from org.eclipse.kura.wire.ScriptFilter-1537884418687-2\nINFO o.e.k.i.w.l.Logger - Record List content:\nINFO o.e.k.i.w.l.Logger - Record content:\nINFO o.e.k.i.w.l.Logger - txPower : -7\nINFO o.e.k.i.w.l.Logger - rssi : -55\nINFO o.e.k.i.w.l.Logger - distance : 251.18864315095797\nINFO o.e.k.i.w.l.Logger - format : 4\nINFO o.e.k.i.w.l.Logger - temperature : 26.0\nINFO o.e.k.i.w.l.Logger - humidity : 42.0\nINFO o.e.k.i.w.l.Logger - pressure : 100000\nINFO o.e.k.i.w.l.Logger - id : 120\nINFO o.e.k.i.w.l.Logger -\nINFO o.e.k.w.s.f.p.ScriptFilter - 04401a00c35078\nINFO o.e.k.i.w.l.Logger - Received WireEnvelope from org.eclipse.kura.wire.ScriptFilter-1537884418687-2\nINFO o.e.k.i.w.l.Logger - Record List content:\nINFO o.e.k.i.w.l.Logger - Record content:\nINFO o.e.k.i.w.l.Logger - txPower : -7\nINFO o.e.k.i.w.l.Logger - rssi : -39\nINFO o.e.k.i.w.l.Logger - distance : 39.810717055349734\nINFO o.e.k.i.w.l.Logger - format : 4\nINFO o.e.k.i.w.l.Logger - temperature : 26.0\nINFO o.e.k.i.w.l.Logger - humidity : 32.0\nINFO o.e.k.i.w.l.Logger - pressure : 100000\nINFO o.e.k.i.w.l.Logger - id : 120\nINFO o.e.k.i.w.l.Logger -\n
In this section a simple but effective example of the GPIO Driver on Wires will be presented. This example will implement a Wire graph that toggles a digital GPIO. A listener will be attached to an input GPIO externally connected to the first one.
Setup a Raspberry Pi as shown in GPIO Driver section. Add a cable from the LED contact near the red cable to pin 37 (gpio 26) on the RaspberryPi.
"},{"location":"kura-wires/usage-examples/gpio-driver-application/#configure-kura-wires-gpio-driver-application","title":"Configure Kura Wires GPIO Driver Application","text":"Install the GPIO Driver from the Eclipse Kura Marketplace.
On the Kura web interface, instantiate a GPIO Driver:
From the \"Drivers and Assets\" tab, add a new asset bound to the GPIO driver:
As in point 3., create a new asset as shown below:
Click on \"Wires\" under \"System\".
Add a new \"Timer\" component and configure the interval at which the LED will be toggled.
Add a new \"Script Filter\" (it can be downloaded from the Eclipse Marketplace and configure it with the following script:
// create a persistent counter\ncounter = typeof(counter) === 'undefined' ? 0 : counter\ncounter++\n\n// emit the counter value in a different WireRecord\nvar counterRecord = newWireRecord()\ncounterRecord.LED = newBooleanValue(counter%2==0)\noutput.add(counterRecord)\n
Add the \"Asset\" created at point 3 and connect the \"Timer\" to the \"Filter\" and the latter to the \"Asset\".
Add the \"Asset\" created at point 4.
Add \"Logger\" component and set log.verbosity to \"VERBOSE\".
Connect the latter \"Asset\" to the \"Logger\". The resulting Wire Graph should be as below:
Click on \"Apply\". After a while, the led on the breadboard should start to blink at a rate defined by the \"Timer\" as shown below:
Moreover, the kura.log file should show a long sequencce of messages reporting that the value from the input gpio is changed:
2018-04-09 13:08:42,990 [Thread-3289] INFO o.e.k.i.w.l.Logger - Received WireEnvelope from org.eclipse.kura.wire.WireAsset-1523276074484-23\n2018-04-09 13:08:42,991 [Thread-3289] INFO o.e.k.i.w.l.Logger - Record List content: \n2018-04-09 13:08:42,992 [Thread-3289] INFO o.e.k.i.w.l.Logger - Record content: \n2018-04-09 13:08:42,993 [Thread-3289] INFO o.e.k.i.w.l.Logger - LED_Feedback : false\n2018-04-09 13:08:42,993 [Thread-3289] INFO o.e.k.i.w.l.Logger - assetName : GPIOAssetFeedback\n2018-04-09 13:08:42,994 [Thread-3289] INFO o.e.k.i.w.l.Logger - LED_Feedback_timestamp : 1523279322990\n2018-04-09 13:08:42,994 [Thread-3289] INFO o.e.k.i.w.l.Logger - \n2018-04-09 13:08:44,988 [Thread-3291] INFO o.e.k.i.w.l.Logger - Received WireEnvelope from org.eclipse.kura.wire.WireAsset-1523276074484-23\n2018-04-09 13:08:44,989 [Thread-3291] INFO o.e.k.i.w.l.Logger - Record List content: \n2018-04-09 13:08:44,989 [Thread-3291] INFO o.e.k.i.w.l.Logger - Record content: \n2018-04-09 13:08:44,989 [Thread-3291] INFO o.e.k.i.w.l.Logger - LED_Feedback : true\n2018-04-09 13:08:44,989 [Thread-3291] INFO o.e.k.i.w.l.Logger - assetName : GPIOAssetFeedback\n2018-04-09 13:08:44,989 [Thread-3291] INFO o.e.k.i.w.l.Logger - LED_Feedback_timestamp : 1523279324988\n
As presented in the iBeacon\u2122 Driver, Kura provides a specific driver that can be used to listen for iBeacons packets. The driver is available only for gateways that support the new Kura BLE APIs.
This tutorial will explain how to configure a Wire graph that get iBeacon\u2122 data and show them to a logger.
"},{"location":"kura-wires/usage-examples/ibeacon-driver-application/#configure-the-wires-ibeacontm-application","title":"Configure the Wires iBeacon\u2122 Application","text":"Install the iBeacon driver from the Eclipse Kura Marketplace.
On the Web Interface, instantiate the iBeacon Driver:
From the \"Drivers and Assets\" tab, add a new asset binded to the iBeacon driver:
Click on the \"New Asset\" button and fill the form with the \"Asset Name\" and selecting the driver created in step 2. as \"Driver Name\". Click \"Apply\" and a new asset will be listed under the iBeacon driver.
Click on the new asset and configure it, adding a single channel that represents a listener for iBeacon\u2122 advertising packets. Check the listen checkbox for the channel.
Click on \"Wires\" under \"System\".
Add a new \"Asset\" with the previously added iBeacon asset.
Add a new \"Javascript Filter\" component. The filter will be configured to parse the iBeacon packets and extract relevant data from it. In the script window write the following code:
var record = input.records[0]\nif (record.ibeacon != null) {\n var values = record.ibeacon.getValue().split(\";\")\n\n if (values.length == 6) {\n var outRecord = newWireRecord()\n outRecord.uuid = newStringValue(values[0]) \n outRecord.txPower = newIntegerValue(parseInt(values[1]))\n outRecord.rssi = newIntegerValue(parseInt(values[2]))\n outRecord.major = newIntegerValue(parseInt(values[3]))\n outRecord.minor = newIntegerValue(parseInt(values[4]))\n outRecord.distance = newDoubleValue(parseFloat(values[5]))\n\n output.add(outRecord)\n }\n}\n
Add \"Logger\" component and set the log.verbosity to VERBOSE
Click on \"Apply\".
Using this graph, every iBeacon packet will be detected and reported to the log, as shown below. To simulate an iBeacon device, it is possible to use another gateway with the iBeacon advertiser example.
INFO o.e.k.i.w.l.Logger - Received WireEnvelope from org.eclipse.kura.wire.WireAsset-1537886139797-15\nINFO o.e.k.i.w.l.Logger - Record List content:\nINFO o.e.k.i.w.l.Logger - Record content:\nINFO o.e.k.i.w.l.Logger - assetName : iBeaconAsset\nINFO o.e.k.i.w.l.Logger - iBeacon : aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee;0;-38;0;0;79.43282347242814\nINFO o.e.k.i.w.l.Logger - iBeacon_timestamp : 1537886424085\nINFO o.e.k.i.w.l.Logger -\nINFO o.e.k.i.w.l.Logger - Received WireEnvelope from org.eclipse.kura.wire.WireAsset-1537886139797-15\nINFO o.e.k.i.w.l.Logger - Record List content:\nINFO o.e.k.i.w.l.Logger - Record content:\nINFO o.e.k.i.w.l.Logger - assetName : iBeaconAsset\nINFO o.e.k.i.w.l.Logger - iBeacon : aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee;0;-42;0;0;125.89254117941674\nINFO o.e.k.i.w.l.Logger - iBeacon_timestamp : 1537886425086\nINFO o.e.k.i.w.l.Logger -\n
This tutorial will describe how to collect data from an OPC-UA device and publish them on a cloud platform using Wires. The OPC-UA server device will be emulated using a bundle running on Kura.
"},{"location":"kura-wires/usage-examples/opcua-application/#configure-opc-ua-server-simulator","title":"Configure OPC-UA server simulator","text":"As presented in the Ti SensorTag Driver, Kura provides a specific driver that can be used to interact with Texas Instruments SensorTag devices. The driver is available only for gateways that support the new Bluetooth LE APIs.
This tutorial will explain how to configure a Wire graph that connects with a SensorTag, reads sensor values and publishes data to a cloud platform.
Warning
The SensorTag driver can be used only with TI SensorTags with firmware version >1.20. If your device has an older firmware, please update it.
"},{"location":"kura-wires/usage-examples/ti-sensortag-application/#configure-the-ti-sensortag-application","title":"Configure the TI SensorTag Application","text":"Install the TI SensorTag driver from the Eclipse Kura Marketplace
On the Kura Administrative Web Interface, instantiate a SensorTag Driver:
org.eclipse.kura.driver.ble.sensortag
as Driver Factory, type a name in Driver Name and click the Apply button: a new driver will be instantiated and listed in the page.In the Drivers and Assets tab add a new asset and associate it to the SensorTag driver:
Click Apply.
Apply the following configuration for the Asset instance:
Create a Wire Graph as in the following picture.
Please note that the driver supports also unsolicited inputs, setting up a notification for the given channel. In this case, it is sufficient to check the listen option for the chosen channel. The Timer is not needed because the SensorTag will automatically emit the values every notification.period milliseconds.
Kura QA activities focused on two main areas:
More on the unit and integration tests can be read in unit testing. More about manual system testing can be read in system testing.
"},{"location":"quality-assurance/system-testing/","title":"System Testing","text":""},{"location":"quality-assurance/system-testing/#qa-procedure","title":"QA Procedure","text":"A set of automated and manual test are performed before releasing a new Eclipse\u2122 Kura version to ensure software follows our quality standards.
Once a Release Candidate (RC) is tagged on its maintenance branch the QA process starts. The QA process involves a set of automated and manual tests performed on the target environment listed below. These tests are updated continuosly to follow the large amount of features added in each release. The QA process continues with new Release Candidate builds until the amount of defects in the software is reduced. When this happens the RC is promoted to final release and tagged on the maintenance branch.
"},{"location":"quality-assurance/system-testing/#environment","title":"Environment","text":""},{"location":"quality-assurance/system-testing/#hardware","title":"Hardware","text":"Build-time testing is further divided into unit testing and integration testing.
Unit testing is focused on testing separate methods or groups of methods, preferably in a single class. This way it can verify the correct operation of difficult-to-reach corner cases.
Integration testing is a more-high-level testing that tests certain functionality on a group of connected services in an approximation of the real environment. It verifies that the services can successfully register in the environment and connect to other services as well as perform their tasks.
Code coverage of the develop branch can be observed in Jenkins.
For some tips on running the tests also check Kura GitHub Wiki.
"},{"location":"quality-assurance/unit-testing/#unit-testing_1","title":"Unit Testing","text":"Unit tests should try to cover as many corner cases in the code as possible. Add them for (all) the new code you decide to contribute.
"},{"location":"quality-assurance/unit-testing/#test-location","title":"Test Location","text":"Kura discourages to introduce test-only dependencies on the implementation level, so all tests are located in their own projects under test/
. The proper folder to put the tests in is src/test/java
.
<package name>.test
as the name of the test project. Add it as a module in test/pom.xml
that also serves as maven artifact's parent.src/main/java
to build.properties' source..
.The basic flow is to build your implementation using maven and then also build and run the unit tests using mvn clean test
(or some other phase e.g. install, which also runs integration tests).
Advanced test running and running them in IDE is described in Kura GitHub Wiki.
"},{"location":"quality-assurance/unit-testing/#integration-testing","title":"Integration Testing","text":"These test proper behavior in the OSGi environment. Some additional configuration is therefore necessary.
"},{"location":"quality-assurance/unit-testing/#test-location_1","title":"Test Location","text":"We don't want to mess with the implementation code here, either, so all tests are again located in the test projects under test/
. It can be the same project as for unit tests. The proper folder to put the tests in is src/main/java
.
<package name>.test
as the name of the test project. Add it as a module in test/pom.xml
that also serves as maven artifact's parent.src/main/java
to build.properties' source..
.<package name>.test
as the package to put the test in. Also add .test
suffix to any subpackages that are also under test.The basic flow is to build your implementation using maven and then also build and run the integration tests using mvn clean install
.
Advanced test running and running them in IDE is described in Kura GitHub Wiki.
"},{"location":"references/javadoc/","title":"Javadoc","text":"This section provides guidelines on how to structure the MQTT topic namespace for messaging interactions with applications running on IoT gateway devices.
Interactions may be solicited by a remote server to the gateway using a request/response messaging model, or unsolicited when the gateway simply reports messages or events to a remote server based on periodic or event-driven patterns.
The table below defines some basic terms used in this document:
Term Descriptionaccount_name
Identifies a group of devices and users. It can be seen as partition of the MQTT topic namespace. For example, access control lists can be defined so that users are only given access to the child topics of a given account_name
. client_id
Identifies a single gateway device within an account (typically the MAC address of a gateway\u2019s primary network interface). The client_id maps to the Client Identifier (Client ID) as defined in the MQTT specifications. app_id
Unique string identifier for application (e.g., \u201cCONF-V1\u201d, \u201cCONF-V2\u201d, etc.). resource_id
Identifies a resource(s) that is owned and managed by a particular application. Management of resources (e.g., sensors, actuators, local files, or configuration options) includes listing them, reading the latest value, or updating them to a new value. A resource_id may be a hierarchical topic, where, for example, \u201csensors/temp\u201d may identify a temperature sensor and \u201csensor/hum\u201d a humidity sensor. A gateway, as identified by a specific client_id and belonging to a particular account_name, may have one or more applications running on it (e.g., \u201capp_id1\u201d, \u201capp_id2\u201d, etc.). Each application can manage one or more resources identified by a distinct resource_id(s).
Based on this criterion, an IoT application running on an IoT gateway may be viewed in terms of the resources it owns and manages as well as the unsolicited events it reports.
"},{"location":"references/mqtt-namespace/#mqtt-requestresponse-conversations","title":"MQTT Request/Response Conversations","text":"Solicited interactions require a request/response message pattern to be established over MQTT. To initiate a solicited conversation, a remote server first sends a request message to a given application running on a specific device and then waits for a response.
To ensure the delivery of request messages, applications that support request/response conversations via MQTT should subscribe to the following topic on startup:
$EDC/account_name/client_id/app_id/#\n
The $EDC prefix is used to mark topics that are used as control topics for remote management. This prefix distinguishes control topics from data topics that are used in unsolicited reports and marks the associated messages as transient (not to be stored in the historical data archive, if present).
Note
While Kura currently requires \u201c$EDC\u201d as the prefix for control topics, this prefix may change in the future for the following reasons:
MQTT 3.1.1 discourages the use of topic starting with \u201c$\u201d for application purposes.
As a binding of LWM2M over MQTT is taking shape, it would make sense to use a topic prefix for management messages like \u201cLWM2M\u201d or similar abbreviations (e.g. \"LW2\u201d, \u201cLWM\u201d).
A requester (i.e., the remote server) initiates a request/response conversation through the following events:
Generating a conversation identifier known as a request.id (e.g., by concatenating a random number to a timestamp)
Subscribing to the topic where the response message will be published, where requester.client.id is the client ID of the requester, such as:
$EDC/account_name/requester.client.id/app_id/REPLY/request.id\n
Sending the request message to the appropriate application-specific topic with the following fields in the payload:
The application receives the request, processes it, and responds on a REPLY topic structured as:
$EDC/account_name/requester.client.id/app_id/REPLY/request.id\n
Note
While this recommendation does not mandate the format of the message payload, which is application-specific, it is important that the request.id and requester.client.id fields are included in the payload. Kura leverages an MQTT payload encoded through Google Protocol Buffers. Kura includes the request.id and the requester.client.id as two named metrics of the Request messages. The Kura payload definition can be found here.
Once the response for a given request is received, the requester unsubscribes from the REPLY topic.
"},{"location":"references/mqtt-namespace/#mqtt-requestresponse-example","title":"MQTT Request/Response Example","text":"The following sample request/response conversation shows the device configuration being provided for an application:
account_name: guest\ndevice client_id: F0:D2:F1:C4:53:DB\napp_id: CONF-V1\nRemote Service Requester client_id: 00:E0:C7:01:02:03\n
The remote server publishes a request message similar to the following:
Request Topic:
Request Payload:
The gateway device replies with a response message similar to the following:
Response Topic:
Response Payload, where the following properties are mandatory:
Note
In addition to the mandatory properties, the response payload may also have custom properties whose description is beyond the scope of this document.
It is recommended that the requester server employs a timeout to control the length of time that it waits for a response from the gateway device. If a response is not received within the timeout interval, the server can expect that either the device or the application is offline.
"},{"location":"references/mqtt-namespace/#mqtt-remote-resource-management","title":"MQTT Remote Resource Management","text":"A remote server interacts with the application\u2019s resources through read, create and update, delete, and execute operations. These operations are based on the previously described request/response conversations.
"},{"location":"references/mqtt-namespace/#read-resources","title":"Read Resources","text":"An MQTT message published on the following topic is a read request for the resource identified by the resource_id:
$EDC/account_name/client_id/app_id/GET/resource_id\n
The receiving application responds with a REPLY message containing the latest value of the requested resource.
The resource_id is application specific and may be a hierarchical topic. It is recommended to design resource identifiers following the best practices established for REST API.
For example, if an application is managing a set of sensors, a read request issued to the topic \"$EDC/account_name/client_id/app_id/GET/sensors\" will reply with the latest values for all sensors.
Similarly, a read request issued to the topic \"$EDC/account_name/client_id/app_id/GET/sensors/temp\" will reply with the latest value for only a temperature sensor that is being managed by the application.
"},{"location":"references/mqtt-namespace/#create-or-update-resources","title":"Create or Update Resources","text":"An MQTT message published on the following topic is a create or update request for the resource identified by the resource_id:
$EDC/account_name/client_id/app_id/PUT/resource_id\n
The receiving application creates the specified resource (or updates it if it already exists) with the value supplied in the message payload and responds with a REPLY message.
As in the read operations, the resource_id is application specific and may be a hierarchical topic. It is recommended to design resource identifiers following the best practices established for REST API. For example, to set the value for an actuator, a message can be published to the topic \"$EDC/account_name/client_id/app_id/PUT/actuator/1\" with the new value suplliied in the message payload.
"},{"location":"references/mqtt-namespace/#delete-resources","title":"Delete Resources","text":"An MQTT message published on the following topic is a delete request for the resource identified by the resource_id:
$EDC/account_name/client_id/app_id/DEL/resource_id\n
The receiving application deletes the specified resource, if it exists, and responds with a REPLY message.
"},{"location":"references/mqtt-namespace/#execute-resources","title":"Execute Resources","text":"An MQTT message published on the following topic is an execute request for the resource identified by the resource_id:
$EDC/account_name/client_id/app_id/EXEC/resource_id\n
The receiving application executes the specified resource, if it exists, and responds with a REPLY message. The semantics of the execute operation is application specific.
"},{"location":"references/mqtt-namespace/#other-operations","title":"Other Operations","text":"The IoT application may respond to certain commands, such as taking a snapshot of its configuration or executing an OS-level command. The following topic namespace is recommended for command operations:
$EDC/account_name/client_id/app_id/EXEC/command_name\n
An MQTT message published with this topic triggers the execution of the associated command. The EXEC message may contain properties in the MQTT payload that can be used to parameterize the command execution.
"},{"location":"references/mqtt-namespace/#mqtt-unsolicited-events","title":"MQTT Unsolicited Events","text":"IoT applications have the ability to send unsolicited messages to a remote server using events to periodically report data readings from their resources, or to report special events and observed conditions.
Tip
It is recommended to not use MQTT control topics for unsolicited events, and subsequently, to avoid the $EDC topic prefix.
Event MQTT topics generally follow the pattern shown below to report unsolicited data observations for a given resource:
account_name/client_id/app_id/resource_id\n
"},{"location":"references/mqtt-namespace/#discoverability","title":"Discoverability","text":"The MQTT namespace guidelines in this document do not address remote discoverability of a given device\u2019s applications and its resources. The described interaction pattern can be easily adopted to define an application whose only responsibility is reporting the device profile in terms of installed applications and available resources.
"},{"location":"references/mqtt-namespace/#remote-osgi-management-via-mqtt","title":"Remote OSGi Management via MQTT","text":"The concepts previously described have been applied to develop a solution that allows for the remote management of certain aspects of an OSGi container through the MQTT protocol, including:
Remote deployment of application bundles
Remote start and stop of services
Remote read and update of service configurations
The following sections describe the MQTT topic namespaces and the application payloads used to achieve the remote management of an OSGi container via MQTT.
Note
For the scope of this document, some aspects concerning the encoding and compressing of the payload are not included.
The applicability of the remote management solution, as inspired by the OSGi component model, can be extended beyond OSGi as the contract with the managing server based on MQTT topics and XML payloads.
"},{"location":"references/mqtt-namespace/#remote-osgi-configurationadmin-interactions-via-mqtt","title":"Remote OSGi ConfigurationAdmin Interactions via MQTT","text":"An application bundle is installed in the gateway to allow for remote management of the configuration properties of the services running in the OSGi container.
For information about the OSGi Configuration Admin Service and the OSGi Meta Type Service, please refer to the OSGi Service Platform Service R7 Specifications.
The app_id for the remote configuration service of an MQTT application is \u201cCONF-V1\u201d. The resources it manages are the configuration properties of the OSGi services. Service configurations are represented in XML format.
The following service configuration XML message is an example of a watchdog service:
<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<ns2:configuration xmlns:ns2=<http://eurotech.com/esf/2.0\n xmlns=<http://www.osgi.org/xmlns/metatype/v1.2.0>\n pid=\"org.eclipse.kura.watchdog.WatchdogService\">\n\n <OCD id=\"org.eclipse.kura.watchdog.WatchdogService\"\n name=\"WatchdogService\"\n description=\"WatchdogService Configuration\">\n\n <Icon resource=\"WatchdogService\"/>\n\n <AD id=\"watchdog.timeout\"\n name=\"watchdog.timeout\"\n required=\"true\"\n default=\"10000\"\n cardinality=\"0\"\n type=\"Integer\"\n description=\"\"/>\n </OCD>\n\n <ns2:properties>\n <ns2:property type=\"Integer\" array=\"false\" name=\"watchdog.timeout\">\n <ns2:value>10000</ns2:value>\n </ns2:property>\n </ns2:properties>\n</ns2:configuration>\n
The service configuration XML message is comprised of the following parts:
The Object Class Definition (OCD), which describes the service attributes that may be configured. (The syntax of the OCD element is described in the OSGi Service Platform Service R7 Specifications)
The properties element, which contains one or more properties with their associated type and values. The type name must match the name provided in the corresponding attribute definition identifier (AD id) contained in the OCD.
The \u201cCONF-V1\u201d application supports the read and update resource operations as described in the following sections.
"},{"location":"references/mqtt-namespace/#read-all-configurations","title":"Read All Configurations","text":"This operation provides all service configurations for which remote administration is supported.
Request Topic:
Request Payload:
Response Payload:
This operation provides configurations for a specific service that is identified by an OSGi service persistent identifier pid.
Request Topic:
Request Payload:
Response Payload:
This operation remotely updates the configuration of a set of services.
Request Topic:
Request Payload:
Response Payload:
This operation remotely updates the configuration of the service identified by a pid.
Request Topic:
Request Payload:
Response Payload:
The previously described read and update resource operations can be leveraged to develop a web application that allows for remote OSGi service configuration updates via MQTT though a web user-interface.
The screen capture that follows shows an example administration application where, for a given IoT gateway, a list of all configurable services is presented to the administrator.
When one such service is selected, a form is dynamically generated based on the metadata provided in the service OCD. This form includes logic to handle different attribute types, validate acceptable value ranges, and render optional values as drop-downs. When the form is submitted, the new values are communicated to the device through an MQTT resource update message.
"},{"location":"references/mqtt-namespace/#remote-osgi-deploymentadmin-interactions-via-mqtt","title":"Remote OSGi DeploymentAdmin Interactions via MQTT","text":"An application is installed in the gateway to allow for the remote management of the deployment packages installed in the OSGi container.
For information about the OSGi Deployment Admin Service, please refer to the OSGi Service Platform Service Compendium 4.3 Specifications.
The app_id for the remote deployment service of an MQTT application is \u201cDEPLOY-V2\u201d. It allows to perform the following operations:
The download request allows to download and optionally install a software package. The installation procedure will be performed after the download completes if the dp.install metric is set to true
. If the metric is set to false
, the installation step will not be performed.
The package type must be specified using the dp.install.system.update request metric, the supported types are the following:
false
.true
.The device will report the download progress and result of the installation to the cloud platform by sending asynchronous download notification messages and install notification messages.
The completion notification logic differs depending on the package type.
OSGi Deployment Package: The completion notification will be sent immediately after that the Deployment Package is installed on the system.
Executable Shell Script: The completion notification will not be sent immediately after that the shell script is executed, but is determined by the execution of an additional verifier script. The verifier script will be executed at next framework startup. A install notification message will be sent afterwards, with dp.install.status = COMPLETED
if the exit status is 0 or dp.install.status = FAILED
otherwise. This is based on the assumption that a system level update will typically require a device restart.
The verifier script can be provided in the following ways:
By specifying a download URL as the value of the dp.install.verifier.uri request metric. In this case the framework will download the verifier script from the provided URL.
By installing it during the execution of the main shell script. In this case the file must be placed in the /opt/eclipse/kura/data/persistance/verification
directory. The installed verifier file name must have the ${name}-${version}.sh_verifier.sh
structure where ${name}
and ${version}
must be replaced with the values of the dp.name and dp.version request metrics.
Warning
As said above, in case of Executable Shell Script, the completion notification will not be sent if the verifier script is not provided and/or the framework is not restarted.
Request:
Request Topic:
Payload:
Response:
The client will reply immediately with an appropriate response.code. If the platform retries the request but the download is in progress, the client will reply that the request is already in progress with a 500 error code. If the DP has already been downloaded, the client will reply that the request has been accepted. If the dp.download.force flag is set to true, the client will start the download from the beginning, if false the device will proceed with the installation.
Payload: no application-specific metrics or body.
Request:
Response:
Request:
Response:
The client will start downloading the DP and will compute the size of the transfer from the HTTP header. This size will be used to estimate the download progress using the request parameter dp.download.block.size. Next, the client will report the download progress to the platform by publishing, with QoS==2, one or more unsolicited messages. If HTTP header is not available, the device will report 50% as dp.download.progress for all the download processes. The value of requester.client.id is one of the last downloads or install request received.
Download Notification:
Request:
Note
This operation can be retried. Anyway, if it fails once it's likely to fail again.
Response:
Request:
Response:
If the value of dp.install in the original download request is true the client will start installing the DP. Due to the limitations of the OSGi DeploymentAdmin, it's not possible to have feedback on the install progress. However, these operations should normally complete in a few seconds, even for an upgrade. Otherwise (dp.install==false), the platform can request the installation of an already downloaded package through the following message:
Install notification:
Request:
Response: The client will reply immediately with an appropriate response.code. If the platform retries the request but the uninstall operation is in progress, the client will reply that the request is already in progress with a 500 error code. At the end of the uninstall operation, an unsolicited message is sent to the cloud platform to report the operation status. If a reboot was requested in the received uninstall request, it will be executed with the specified delay.
"},{"location":"references/mqtt-namespace/#unsolicited-messages-for-uninstall-progress","title":"Unsolicited messages for uninstall progress","text":"Uninstall notification:
This operation provides all the bundles installed in the OSGi framework.
The following XML message is an example of a bundle:
<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<bundles>\n <bundle>\n <name>org.eclipse.osgi</name>\n <version>3.8.1.v20120830-144521</version>\n <id>0</id>\n <state>ACTIVE</state>\n </bundle>\n <bundle>\n <name>org.eclipse.equinox.cm</name>\n <version>1.0.400.v20120522-1841</version>\n <id>1</id>\n <state>ACTIVE</state>\n </bundle>\n</bundles>\n
The bundle XML message is comprised of the following bundle elements:
This operation starts a bundle identified by its ID.
This operation stops a bundle identified by its ID.
The previously described read, start/stop, and install/uninstall resources can be used to implement a remote management application. An example of such application is Eclipse Kapua. In particular it is possible to use the download and install resources from the following sections in Eclipse Kapua console:
Selecting the Devices section, a target device, and then clicking on the Install button in the Packages tab will allow to send download and install requests.
It is possible to create a batch job with the Package Download / Install definition to perform a download / install request on a set of target devices.
"},{"location":"references/mqtt-namespace/#remote-gateway-inventory-via-mqtt","title":"Remote Gateway Inventory via MQTT","text":"An application is installed in the gateway to allow for the remote query of the resources installed in the OSGi container and the underlying OS.
The app_id for the remote inventory service of an MQTT application is \u201cINVENTORY-V1\u201d. The service allows retrieving all the different resources available/installed on the gateway. The service supports the following resources:
The resources are represented in JSON format. The following message is an example of a service deployment:
{\n \"inventory\":[\n {\n \"name\":\"adduser\",\n \"version\":\"3.118\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"io.netty.transport-native-unix-common\",\n \"version\":\"4.1.34.Final\",\n \"type\":\"BUNDLE\"\n },\n ]\n}\n
The inventory JSON message is comprised of the following package elements:
Name
Version
Type
The \u201cINVENTORY-V1\u201d application supports only the read resource operations as described in the following sections.
"},{"location":"references/mqtt-namespace/#inventory-bundles","title":"Inventory Bundles","text":""},{"location":"references/mqtt-namespace/#read-all-bundles_1","title":"Read All Bundles","text":"This operation provides all the bundles installed in the OSGi framework.
Request Topic:
Request Payload:
Response Payload:
The following JSON message is an example of a bundle:
{\n \"bundles\":[\n {\n \"name\":\"org.eclipse.osgi\",\n \"version\":\"3.16.0.v20200828-0759\",\n \"id\":0,\n \"state\":\"ACTIVE\",\n \"signed\":true\n },\n {\n \"name\":\"org.eclipse.equinox.cm\",\n \"version\":\"1.4.400.v20200422-1833\",\n \"id\":1,\n \"state\":\"ACTIVE\",\n \"signed\":false\n }\n ]\n}\n
The bundle JSON message is comprised of the following bundle elements:
Symbolic name
Version
ID
State
Signed
This operation allows to start a bundles installed in the OSGi framework.
Request Topic:
Request Payload:
Response Payload:
Request Topic:
Request Payload:
Response Payload:
The requests for starting and stopping a bundle require the application to include a JSON object in request payload for selecting the target bundle, the defined properties are the following:
If multiple bundles match the selection criteria, only one of them will be stopped/started, which one is not defined.
Examples:
{\n \"name\":\"org.eclipse.kura.example.beacon\"\n}\n
{\n \"name\":\"org.eclipse.kura.example.beacon\",\n \"version\":\"1.0.500\"\n}\n
"},{"location":"references/mqtt-namespace/#inventory-deployment-packages","title":"Inventory Deployment Packages","text":""},{"location":"references/mqtt-namespace/#read-all-deployment-packages","title":"Read All Deployment Packages","text":"This operation provides the deployment packages installed in the OSGi framework.
Request Topic:
Request Payload:
Response Payload:
The following JSON message is an example of a bundle:
{\n \"deploymentPackages\":[\n {\n \"name\":\"org.eclipse.kura.example.beacon\",\n \"version\":\"1.0.500\",\n \"signed\":false,\n \"bundles\":[\n {\n \"name\":\"org.eclipse.kura.example.beacon\",\n \"version\":\"1.0.500\",\n \"id\": 171,\n \"state\": \"ACTIVE\",\n \"signed\": false\n }\n ]\n }\n ]\n}\n
The deployment package JSON message is comprised of the following package elements:
Symbolic name
Version
Signature: true if all the bundles in the deployment package are signed
Bundles that are managed by the deployment package along with their symbolic name and version
This operation provides the Linux packages installed in OS.
Request Topic:
Request Payload:
Response Payload:
The following JSON message is an example of a bundle:
{\n \"systemPackages\":[\n {\n \"name\":\"adduser\",\n \"version\":\"3.118\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"alsa-utils\",\n \"version\":\"1.1.8-2\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"ansible\",\n \"version\":\"2.7.7+dfsg-1\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"apparmor\",\n \"version\":\"2.13.2-10\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"apt\",\n \"version\":\"1.8.2.1\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"apt-listchanges\",\n \"version\":\"3.19\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"apt-transport-https\",\n \"version\":\"1.8.2.2\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"apt-utils\",\n \"version\":\"1.8.2.1\",\n \"type\":\"DEB\"\n }\n ]\n}\n
The bundle JSON message is comprised of the following bundle elements:
Name
Version
Type
Using the API exposed by Inventory-V1, the user can manage containers via external applications such as Eclipse Kapua. This operation lists all the containers installed in the gateway.
The following JSON message is an example of what this request outputs:
{\n \"containers\":\n [\n {\n \"name\":\"container_1\",\n \"version\":\"nginx:latest\",\n \"type\":\"DOCKER\",\n \"state\":\"active\"\n }\n ]\n}\n
The container JSON message is comprised of the following elements:
Name: The name of the docker container.
Version: describes both the container's respective image and tag separated by a colon.
Type: denotes the type of inventory payload
State: describes the container's current state
active
: Container is runninginstalled
: Container is startinguninstalled
: Container has failed, or is stoppedunknown
: Container state can not be determinedThis operation allows starting a container installed on the gateway. * Request Topic * $EDC/account_name/client_id/INVENTORY-V1/EXEC/containers/_start * Request Payload * A JSON object that identifies the target container must be specified in the payload body. This payload will be described in the following section * Response Payload * Nothing application-specific
"},{"location":"references/mqtt-namespace/#stop-a-container","title":"Stop a Container","text":"The requests for starting and stopping a container require the application to include a JSON object in the request payload for selecting the target container. Docker enforces unique container names on a gateway, and thus they can reliably be used as an identifier.
Examples:
{\n \"name\":\"container_1\",\n \"version\":\"nginx:latest\",\n \"type\":\"DOCKER\",\n \"state\":\"active\"\n}\n
{\n \"name\":\"container_1\",\n}\n
"},{"location":"references/mqtt-namespace/#inventory-container-images","title":"Inventory Container Images","text":""},{"location":"references/mqtt-namespace/#list-all-images","title":"List All Images","text":"Using the API exposed by Inventory-V1, the user can manage container images via external applications such as Eclipse Kapua. This operation lists all the images in the gateway.
The following JSON message is an example of what this request outputs:
{\n \"images\":\n [\n {\n \"name\":\"nginx\",\n \"version\":\"latest\",\n \"type\":\"CONTAINER_IMAGE\"\n }\n ]\n}\n
The container JSON message is comprised of the following elements:
Name: The name of the container image.
Version: describes the container image's version.
Type: denotes the type of inventory payload
This operation allows deleting a container image not in use on the gateway. * Request Topic * $EDC/account_name/client_id/INVENTORY-V1/EXEC/images/_delete * Request Payload * A JSON object that identifies the target image must be specified in the payload body. This payload will be described in the following section * Response Payload * Nothing application-specific
"},{"location":"references/mqtt-namespace/#json-identifierpayload-for-container-image-delete-requests","title":"JSON identifier/payload for container image delete requests","text":"The requests for deleting a container image require the application to include a JSON object in the request payload for selecting the target. The JSON requires both name and version fields to be populated.
Examples:
{\n \"name\":\"nginx\",\n \"version\":\"latest\",\n \"type\":\"CONTAINER_IMAGE\"\n}\n
{\n \"name\":\"nginx\",\n \"version\":\"latest\",\n}\n
"},{"location":"references/mqtt-namespace/#inventory-summary","title":"Inventory Summary","text":""},{"location":"references/mqtt-namespace/#read-all-resources","title":"Read All Resources","text":"This operation provides a list of all the resources installed on the gateway
Request Topic:
Request Payload:
Response Payload:
The following JSON message is an example of a bundle:
{\n \"inventory\":[\n {\n \"name\":\"adduser\",\n \"version\":\"3.118\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"com.eclipsesource.jaxrs.provider.gson\",\n \"version\":\"2.3.0.201602281253\",\n \"type\":\"BUNDLE\"\n },\n {\n \"name\":\"org.eclipse.kura.example.beacon\",\n \"version\":\"1.0.500\",\n \"type\":\"DP\"\n }\n ]\n}\n
The bundle JSON message is comprised of the following bundle elements:
Name
Version
Type
The KEYS-V1 app-id is exposed by the org.eclipse.kura.core.keystore
bundle. This request handler allows the remote management platform to get a list of all the KeystoreService instances and corresponding keys managed by the framework in a given device.
The request handler allows, also, to install new trusted certificate and to generate new key pairs directly in the device. Finally, the remote platform can request, from a defined key pair, the generation of a CSR that can be countersigned remotely by a trusted CA.
"},{"location":"references/mqtt-namespace/#read-all-the-kestoreservices","title":"Read All the KestoreServices","text":"This operation returns the list of all the KeystoreServices instantiated in the framework.
Request Topic:
Request Payload:
Response Payload:
The following JSON message is an example of an output provided:
[\n {\n \"id\": \"org.eclipse.kura.core.keystore.SSLKeystore\",\n \"type\": \"jks\",\n \"size\": 4\n },\n {\n \"id\": \"org.eclipse.kura.crypto.CryptoService\",\n \"type\": \"jks\",\n \"size\": 3\n },\n {\n \"id\": \"org.eclipse.kura.core.keystore.HttpsKeystore\",\n \"type\": \"jks\",\n \"size\": 1\n },\n {\n \"id\": \"org.eclipse.kura.core.keystore.DMKeystore\",\n \"type\": \"jks\",\n \"size\": 1\n }\n]\n
Each entry of the array is specified by the following values: This operation returns the list of all the key entries managed by the framework. If a request payload is specified, the list of entries is filtered based on the parameters in the request
Request Topic:
Request Payload:
{\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.SSLKeystore\"\n}\n
{\n\"alias\": \"ca-godaddyclass2ca\"\n}\n
Response Payload:
The following JSON message is an example of an output provided in the response body:
[\n {\n \"subjectDN\": \"OU=Go Daddy Class 2 Certification Authority, O=\\\"The Go Daddy Group, Inc.\\\", C=US\",\n \"issuer\": \"OU=Go Daddy Class 2 Certification Authority,O=The Go Daddy Group\\\\, Inc.,C=US\",\n \"startDate\": \"Tue, 29 Jun 2004 17:06:20 GMT\",\n \"expirationDate\": \"Thu, 29 Jun 2034 17:06:20 GMT\",\n \"algorithm\": \"SHA1withRSA\",\n \"size\": 2048,\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.SSLKeystore\",\n \"alias\": \"ca-godaddyclass2ca\",\n \"type\": \"TRUSTED_CERTIFICATE\"\n },\n {\n \"algorithm\": \"RSA\",\n \"size\": 4096,\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.HttpsKeystore\",\n \"alias\": \"localhost\",\n \"type\": \"PRIVATE_KEY\"\n }\n]\n
"},{"location":"references/mqtt-namespace/#read-key-details","title":"Read Key Details","text":"This operation returns the details associated to a specified key in a keystore
Request Topic:
Request Payload:
keystoreServicePid
and the alias
of the desired key {\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.HttpsKeystore\"\n \"alias\": \"localhost\"\n}\n
* Response Payload: * List of all the details associated to a key managed by the framework The following JSON message is an example of an output provided:
{\n \"algorithm\": \"RSA\",\n \"size\": 4096,\n \"certificateChain\": [\n \"-----BEGIN CERTIFICATE-----\\nMIIFkTCCA3mgAwIBAgIECtXoiDANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJJ\\nVDELMAkGA1UECBMCVUQxDjAMBgNVBAcTBUFtYXJvMREwDwYDVQQKEwhFdXJvdGVj\\naDEMMAoGA1UECxMDRVNGMQwwCgYDVQQDEwNFU0YwHhcNMjEwNDIyMTUxNTU1WhcN\\nMjQwMTE3MTUxNTU1WjBZMQswCQYDVQQGEwJJVDELMAkGA1UECBMCVUQxDjAMBgNV\\nBAcTBUFtYXJvMREwDwYDVQQKEwhFdXJvdGVjaDEMMAoGA1UECxMDRVNGMQwwCgYD\\nVQQDEwNFU0YwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC7iZ3fHUQa\\nTPgnvSxGZK4f6MZYfLclD74yqaCCWAztNxPQoiBoSPGdsBGBLNeFbwY0Yzg3qwXw\\nYvgzLJmoXV9rSix7LgXPzsSYfUGfu7PeYTy5bG9X2UVyw9LloUM5DKnw++5F7Xy7\\nF0KQQi0z6/HbbPkZ2aGyNRtMCTh1iAGy3gDh/mMnjpUYuoq1luoX1x6I77X0C+NP\\nTxldVYrTeQiswItAHZmkK1R8AYedbFBgjDuTrfRODxBwESn4kQSMLJ8yHYDRm8S6\\ngVz5LdkcM48UiV5hhF+bCD3UvYA00ZgZm2oOG1ONchYrE7pJr7eQVCYaXkS1lALB\\nKaVJzn03wiLJJv1FYLmGt5J/MwfqyCtBTLlieEVfwnxFCkymtews6SYK32e9q/uJ\\nfcdpWH7tOoarnAf7j5mE84rRU3HqzghK0bMxntfrSH3t18ZUt1/4Qx78WfiM1Te3\\nJtnWBqUNJtX6lgT8IxTWwyEqD183tyKIo8hPGyeJrzWA5RL5hYF5rCNTWzqz5Upi\\n0b/YI5K09+Rn8XmEzzaWjFq5zu6/WpqwPRA8kc2RAEA2scnOT+3yl9Lof/M7BrfL\\nMdjVOZ4MfXgl/fhFyd16AObXuZRUIeiWowKtEiNaiUn8paLDxG+LNV7p5wEQCZZI\\n+MsXMMp6G8Te4yILLCcGov7OkO2wx4GPWQIDAQABo2EwXzAxBgNVHSUEKjAoBggr\\nBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDBggrBgEFBQcDCDALBgNVHQ8EBAMC\\nAvwwHQYDVR0OBBYEFKM5PlHoe8qFC6w0quGacazGWE/LMA0GCSqGSIb3DQEBCwUA\\nA4ICAQBvpXmbS9LN8n0A+uq+tM3CNtF3YotWRbQHIGJAFTvdq3003W3CVdmykFc8\\n9Kz8PoY1swBJms7GKjQLkqgTHoq6jU/cIXw+CoLQWmvAugva5C1u/5AHJZqTC06J\\nGZyn1Z9N5Lp0XcgogEyhxdbkHniv7jvcmbCurQijZc9nsd5St7e1pT0Co7KKI6Ff\\nODdVP6kZYBzKo4t20tATdAZJ8t7YHNKNq7ZVs1ej9oYUmmQieNXuE4UoHe5hzVQw\\n567cNHWcTHJoyPve03TSQV91wp5rRUKZm2p0WtFNuv22f5p5sQmttsJltzHCgTwE\\nK0j6qYKnXiq+EQs0A3uF9uiIB/KEDLjxscstqsQGFCFOmjA3GSbmJiKCnss3HkNn\\naknT7XCV6tqgDOfPnNzbWJODjYZ+V0DyNY5uqkG2cyREm/qGbH1kLEXhqdWbKqEs\\nsdW6x8p0ImTaPuRl3XEmXbolavIq+FTtOSz8vW1PsdD3quO6krrwiQMXKv1ZMjup\\nDGIZZ4hUUhN84efjlZyoFRvPRvZ8YvjjrHXLij0vcRxndlicevwl5ezlm0LBOpsT\\nkI2uWrbSbxlue/XdgwFCbN0+mXX88fGj6cjhpvd/xnwHaDHfSG9UoU149LJb6ZIZ\\nru+07QriQQxK8V7AdPr6bhmKPxbbFenvSQmsmgjAY93qtanbNg==\\n-----END CERTIFICATE-----\"\n ],\n \"keystoreServicePid\": \"org.eclipse.kura.core.keystore.HttpsKeystore\",\n \"alias\": \"localhost\",\n \"type\": \"PRIVATE_KEY\"\n}\n
"},{"location":"references/mqtt-namespace/#create-csr","title":"Create CSR","text":"This operation returns the CSR for a specific key pair managed by the framework
Request Topic:
Request Payload:
{ \n \"keystoreServicePid\":\"org.eclipse.kura.core.keystore.HttpsKeystore\",\n \"alias\":\"localhost\",\n \"signatureAlgorithm\" : \"SHA256withRSA\",\n \"attributes\" : \"CN=Kura, OU=IoT, O=Eclipse, C=US\"\n}\n
Response Payload:
-----BEGIN CERTIFICATE REQUEST-----\nMIIEgTCCAmkCAQAwPDELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VjbGlwc2UxDDAK\nBgNVBAsTA0lvVDENMAsGA1UEAxMES3VyYTCCAiIwDQYJKoZIhvcNAQEBBQADggIP\nADCCAgoCggIBAICTNbBm2wIV/TvddB3OW2s2WJmhAOBxwDSdpxGpgWDzmFAydCt5\nSfWCIeC0kmQfrJpcvcIB7IoE2I7HWtIOxV9c+E+n6R76NvdBQzB8enFfZu4ahIKy\nul2VXQSj0VtYLZvG3yx6af4j8UFWsf2AuAe5Fd1dSBq9aEoRU/D5/uNQOQJi45Hk\nds1KK0FcTkfPjugUCLf1Uf0xXnK1V7yZGrgDpPDbZAYCrcsGomdziO8zkE88gKaa\noC1madGL44yz5tiHTKvbf+O+fKc31N4iDvnIg8f87IMF0D4afDF+3AJjVfcFtp3Q\nxWP3zpKqzPzpzWagTzsW446YMxamZgkDxLsVLitQtesom4ON3HT8s+jxHQhCO5LR\n83Ge10+6viJtkp20GYCqANO85c3TaD9njOE0y8P/T7Nk8MwnBbVgwa15QEWRqjEd\nHB6dF5jKdxlfZhPe2AVnLWAd/W96tCIBSqYu6TTH8npprp/S4t10tRkpaLGa+24c\nVlsjR6AFUX4KksvE/mbXd9QsvKgw/h3g4Jly4W/Ourt1LAH19tzGwULNCS7Ft9rp\nIXUsbmUUwb0V3B3ptcJUDzPUw8LdbItPnXzaPegxmkHO8IllcrdRBXrpcTwJl1ug\nMTMWKW/UjUwKcNQ0mGIxQ18aS0mHk8x8bVTnYLcCnGq3NeiFWvOiJIJpAgMBAAGg\nADANBgkqhkiG9w0BAQsFAAOCAgEATsHVZAEjkMSpwozWbVvDw4iJOSYaQ7ZJXhGZ\nn81puMy/kcdNVD2hfG2c4ern8KPib6hYd1mbQpyNtsbJ68VOPIYOdiaqFd7+lbtM\nIVNETBA9ezXzzXwPCtiJYpmeDYz6HfIzRRzuoJhZtOrgyw8v5wiM0NkenDbTQs4l\nOd/YPFlHnEDkTNM+B/ZJJxRIg3sPhAAgj5HH0Mj2053z66hLDYAo4Tos98MwUcuA\ndY1pcs3brxg6z7xz4vbNKyj0Lh8Gua92OSbl1AFZYb6KXm/7+Md0la/YD+K/E2n6\nhUAcHkr3ayNuTI6lkQFptCHzb4Zr8rdbu63JRno9PFTnW+fa/0xi35DoHD2SAhwA\nCUGXTR+HQXkzB/9NE9X0TxS8SwyrE8sfw4usZm25tACdZ33xziqJXOmbChETyL2b\nJ1IcbsHaeN2Shjnj7UQj+hQFnjVwRLTd0zWMN/l7mPj6TiW9ehubE8ce5siHW7NO\nmqJU1bklxTefefSNHTXrvTInuDXT81gLBRE3x+6uqU2kkJnL8jkrkebDDBhYF+qO\n6dB4W5WGbEHxorX2qfjImvy2Ohsl3rL/DqJgqECZaubTz1Xcj/kl9bdxs0pfa6IY\nInre5iom9bGcA6W6U34jRsrE2pobi6c9Yimrbr/R2O/8Oy2k94FQta8tg8jbAxBi\nZ0Vd1nM=\n-----END CERTIFICATE REQUEST-----\n
This operation stores the provided certificate as a Trusted Certificate Entry managed by the framework
Request Topic:
Request Payload:
{\n \"keystoreServicePid\":\"MyKeystore\",\n \"alias\":\"myCertTest99\",\n \"certificate\":\"-----BEGIN CERTIFICATE-----\n MIIDdzCCAl+gAwIBAgIEQsO0gDANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdV\n bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD\n VQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3du\n MB4XDTIxMDQxNDA4MDIyOFoXDTIxMDcxMzA4MDIyOFowbDEQMA4GA1UEBhMHVW5r\n bm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UE\n ChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCC\n ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJSWJDxu8UNC4JGOgK31WCvz\n NKy2ONH+jTVKnBY7Ckb1hljJY0sKO55aG1HNDfkev2lJTsPIz0nJjNsqBvB1flvf\n r6XVCxdN0yxvU5g9SpRxE/iiPX0Qt7463OfzyKW97haJrrhF005RHYNcORMY/Phj\n hFDnZhtAwpbQLzq2UuIZ7okJsx0IgRbjH71ZZuvYCqG7Ct/bp1D7w3tT7gTbIKYH\n ppQyG9rJDEh9+cr9Hyk8Gz7aAbPT/wMH+/vXDjH2j/M1Tmed0ajuGCJumaTQ4eHs\n 9xW3B3ugycb6e7Osl/4ESRO5RQL1k2GBONv10OrKDoZ5b66xwSJmC/w3BRWQ1cMC\n AwEAAaMhMB8wHQYDVR0OBBYEFPospETb5HNeD/DmS9mwt+v/AYq/MA0GCSqGSIb3\n DQEBCwUAA4IBAQBxMe1xQVQKt36A5qVlEZyxI9eb6eQRlYzorOgP2tFaOsvDPpRI\n CALhPmxgQl/5QvKFfCXKoxWj1Spg4sF6fJp6jhSjLpmChS9lf5fRaWS20/pxIddM\n 10diq3r6HxLKSxCYK7Pf5scOeZquvwfo8Kxye01bvCMFf1s1K3ZEZszk5Oo2MnWU\n U22YnXfZm1C0h2WMUcou35A7CeVAHPWI0Rvefojv1qYlQScJOkCN5lO6C/1qvRhq\n nDQdQN/m1HQbpfh2DD6F33nBjkyLQyMRF8uMnspLrLLj8lecSTJZO4fGJOaIXh3O\n 44da9A02FAf5nRRQpwP2x/4IZ5RTRBzrqbqD\n -----END CERTIFICATE-----\"\n}\n
Response Payload:
This operation will generate a new key pair directly in the device, based on the parameters received from the request
Request Topic:
Request Payload:
{\n \"keystoreServicePid\":\"MyKeystore\",\n \"alias\":\"keypair1\",\n \"algorithm\" : \"RSA\",\n \"size\": 1024,\n \"signatureAlgorithm\" : \"SHA256WithRSA\",\n \"attributes\" : \"CN=Kura, OU=IoT, O=Eclipse, C=US\"\n}\n
Response Payload:
This operation will delete the specified entry from the framework managed keystores
Request Topic:
Request Payload:
{\n \"keystoreServicePid\" : \"MyKeystore\",\n \"alias\" : \"mycerttestec\"\n}\n
Response Payload:
Starting from Kura 5.4.0, the KEYS-V2
request handler is also available, it supports all of the request endpoints of KEYS-V1
plus an additional endpoint that allows to upload and modify private key entries:
Request Topic:
Request Payload:
The request should include the private key in unencrypted PEM format and the certificate chain in PEM format, the first certificate in the certificateChain
list must use the public key associated with the private key supplied as the privateKey
parameter.
The device will overwrite the entry with the provided alias if it already exists.
{\n \"keystoreServicePid\":\"MyKeystore\",\n \"alias\":\"keypair1\",\n \"privateKey\":\"-----BEGIN RSA PRIVATE KEY-----\\n...\\n-----END RSA PRIVATE KEY-----\",\n \"certificateChain\":[\n \"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\",\n \"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\",\n ]\n}\n
Response Payload:
Request Topic:
Request Payload:
In order to update the certificate chain associated to a specific private key entry it is possible to use the same format as previous request and omit the privateKey
parameter.
In this case the certificate chain of the existing entry will be replaced with the one specified in the request and the existing private key will be retained.
This request can be useful for example to create a CSR on the device, sign it externally and then updating the corresponding entry with the resulting certificate.
{\n \"keystoreServicePid\":\"MyKeystore\",\n \"alias\":\"keypair1\",\n \"certificateChain\":[\n \"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\",\n \"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\",\n ]\n}\n
Response Payload:
Note
This API can also be accessed via the RequestHandler with app-id: CLD-V1
.
The CloudConnectionRestService
APIs provides methods to manage cloud connection related components like CloudEndpoint
, CloudPublisher
and CloudSubscriber
instances.
Identities with rest.cloudconnection
permissions can access these APIs.
services/cloudconnection/v1/instances
{\n \"cloudEndpointInstances\": [\n {\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloud.CloudService\",\n \"cloudEndpointPid\": \"org.eclipse.kura.cloud.CloudService\",\n \"state\": \"DISCONNECTED\",\n \"cloudEndpointType\": \"CLOUD_CONNECTION_MANAGER\"\n },\n {\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloud.CloudService\",\n \"cloudEndpointPid\": \"org.eclipse.kura.cloud.CloudService-todelete\",\n \"state\": \"DISCONNECTED\",\n \"cloudEndpointType\": \"CLOUD_CONNECTION_MANAGER\"\n },\n {\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloud.CloudService\",\n \"cloudEndpointPid\": \"org.eclipse.kura.cloud.CloudService-2\",\n \"state\": \"DISCONNECTED\",\n \"cloudEndpointType\": \"CLOUD_CONNECTION_MANAGER\"\n },\n {\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloud.CloudService\",\n \"cloudEndpointPid\": \"org.eclipse.kura.cloud.CloudService-3\",\n \"state\": \"DISCONNECTED\",\n \"cloudEndpointType\": \"CLOUD_CONNECTION_MANAGER\"\n },\n {\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloud.CloudService\",\n \"cloudEndpointPid\": \"org.eclipse.kura.cloud.CloudService-test\",\n \"state\": \"DISCONNECTED\",\n \"cloudEndpointType\": \"CLOUD_CONNECTION_MANAGER\"\n }\n ],\n \"pubsubInstances\": [\n {\n \"cloudEndpointPid\": \"org.eclipse.kura.cloud.CloudService\",\n \"pid\": \"testPub\",\n \"factoryPid\": \"org.eclipse.kura.cloud.publisher.CloudPublisher\",\n \"type\": \"PUBLISHER\"\n },\n {\n \"cloudEndpointPid\": \"org.eclipse.kura.cloud.CloudService\",\n \"pid\": \"testPub\",\n \"factoryPid\": \"org.eclipse.kura.cloud.publisher.CloudPublisher\",\n \"type\": \"SUBSCRIBER\"\n }\n ]\n}\n
cloudEndpointType
: The possible values are:
CLOUD_CONNECTION_MANAGER if the component implements CloudConnectionManager
CLOUD_ENDPOINT otherwise.
If cloudEndpointType
is CLOUD_CONNECTION_MANAGER, it is possible to use the cloudEndpoint/connect
, cloudEndpoint/disconnect
and cloudEndpoint/isConnected
methods to manage the connection state.
services/cloudconnection/v1/factories
{\n \"cloudConnectionFactories\": [\n {\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloud.CloudService\",\n \"defaultCloudEndpointPid\": \"org.eclipse.kura.cloud.CloudService-2\",\n \"cloudEndpointPidRegex\": \"^org.eclipse.kura.cloud.CloudService\\\\-[a-zA-Z0-9]+$\"\n },\n {\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager\",\n \"defaultCloudEndpointPid\": \"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager\",\n \"cloudEndpointPidRegex\": \"^org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager(\\\\-[a-zA-Z0-9]+)?$\"\n },\n {\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint\",\n \"defaultCloudEndpointPid\": \"org.eclipse.kura.cloudconnection.raw.mqtt.CloudEndpoint\",\n \"cloudEndpointPidRegex\": \"^org.eclipse.kura.cloudconnection.raw.mqtt.CloudEndpoint(\\\\-[a-zA-Z0-9]+)?$\"\n },\n {\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.camel.cloud.factory.CamelFactory\",\n \"defaultCloudEndpointPid\": \"org.eclipse.kura.camel.cloud.factory.CamelFactory\",\n \"cloudEndpointPidRegex\": \"^org.eclipse.kura.camel.cloud.factory.CamelFactory(\\\\-[a-zA-Z0-9]+)?$\"\n }\n ],\n \"pubSubFactories\": [\n {\n \"factoryPid\": \"org.eclipse.kura.cloudconnection.raw.mqtt.subscriber.RawMqttSubscriber\",\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint\"\n },\n {\n \"factoryPid\": \"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher\",\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager\",\n \"defaultPid\": \"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher\",\n \"defaultPidRegex\": \"^org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher(\\\\-[a-zA-Z0-9]+)?$\"\n },\n {\n \"factoryPid\": \"org.eclipse.kura.cloud.subscriber.CloudSubscriber\",\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloud.CloudService\"\n },\n {\n \"factoryPid\": \"org.eclipse.kura.cloud.publisher.CloudPublisher\",\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloud.CloudService\"\n },\n {\n \"factoryPid\": \"org.eclipse.kura.cloudconnection.raw.mqtt.publisher.RawMqttPublisher\",\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint\"\n },\n {\n \"factoryPid\": \"org.eclipse.kura.event.publisher.EventPublisher\",\n \"cloudConnectionFactoryPid\": \"org.eclipse.kura.cloud.CloudService\"\n }\n ]\n}\n
For cloudConnectionFactories
elements:
cloudConnectionFactoryPid
: the PID of the cloud connection factorydefaultCloudEndpointPid
: If set, it represents the default PID for an instance of a new component suggested by the factory. This can be used by an user interface as a suggestion/placeholder for the name of a new cloud endpoint.cloudEndpointPidRegex
: If set, its value represents a regular expression that the PID of a new component must match.For pubSubFactories
elements:
factoryPid
: The factory PID of the publisher/subscripter component. It identifies the component type. It can be used for example to create a new component using the pubSub
POST method.cloudConnectionFactoryPid
: Specifies the cloudConnectionFactoryPid
of the CloudConnectionFactory associated with this component. Each publisher/subscriber component is only compatible with CloudEndpoint instances created by the factory having this cloudConnectionFactoryPid
.defaultPid
: If set, it represents the default PID for an instance of a new component suggested by the factory. This can be used by an user interface as a suggestion/placeholder for the name of a new publisher/subscriber.defaultPidRegex
: If set, its value represents a regular expression that the PID of a new component must match.
500 Internal Server error
services/cloudconnection/v1/cloudEndpoint/stackComponentPids
{\n \"cloudConnectionFactoryPid\" : \"org.eclipse.kura.cloud.CloudService\",\n \"cloudEndpointPid\": \"org.eclipse.kura.cloud.CloudService\"\n}\n
"},{"location":"references/rest-apis/rest-cloudconnection-api/#responses_2","title":"Responses","text":"{\n \"pids\": [\n \"org.eclipse.kura.cloud.CloudService\",\n \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\",\n \"org.eclipse.kura.data.DataService\"\n ]\n}\n
cloudConnectionFactoryPid
or cloudEndpointPid
are not foundcloudEndpointPid
and optionally other associated stack components, for example CloudService, DataService, DataTransportService.services/cloudconnection/v1/cloudEndpoint
{\n \"cloudConnectionFactoryPid\" : \"org.eclipse.kura.cloud.CloudService\",\n \"cloudEndpointPid\" : \"org.eclipse.kura.cloud.CloudService-1\"\n}\n
cloudEndpointPid
: The cloudEndpointPid
of the new instance that will be created. If the associated factory specifies the cloudEndpointPidRegex
property, this parameter must match the provided regex.cloudConnectionFactoryPid
: The cloudConnectionFactoryPid
of the factory that should be used to create the new component.cloudConnectionFactoryPid
or cloudEndpointPid
.cloudConnectionFactoryPid
services/cloudconnection/v1/pubSub
{\n \"pid\" : \"testPub\",\n \"factoryPid\" : \"org.eclipse.kura.cloud.publisher.CloudPublisher\",\n \"cloudEndpointPid\" : \"org.eclipse.kura.cloud.CloudService\"\n}\n
pid
: The PID of the new publisher/subscriber component. If the publisher/subscriber factory specifies the defaultPidRegex
property, this parameter must match the provided regex.factoryPid
: The factoryPid
of the publisher/subscriber factory.cloudEndpointPid
: The PID of the CloudEndpoint that the new publisher/subscriber component will be associated with. The associated CloudEndpoint must have been created by the CloudConnectionFactory with the cloudConnectionFactoryPid
specified by the publisher/subscriber factory.pid
, factoryPid
or cloudEndpointPid
factoryPid
or cloudEndpointPid
are wrong.cloudEndpoint/stackComponentPids
method.services/cloudconnection/v1/configurations
{\n \"pids\" : [\"testPub\", \"org.eclipse.kura.cloud.CloudService\"]\n}\n
"},{"location":"references/rest-apis/rest-cloudconnection-api/#responses_5","title":"Responses","text":"{\n \"configs\": [\n {\n \"pid\": \"testPub\",\n \"definition\": {\n \"ad\": [\n {\n \"name\": \"Application Id\",\n \"description\": \"The application id used to publish messages.\",\n \"id\": \"appId\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"W1\",\n \"isRequired\": true\n },\n {\n \"name\": \"Application Topic\",\n \"description\": \"Follows the application Id and specifies the rest of the publishing topic. Wildcards can be defined in the topic by specifing a $value in the field. The publisher will try to match \\\"value\\\" with a corresponding property in the received KuraMessage. If possible, the $value placeholder will be substituted with the real value specified in the KuraMessage received from the user application.\",\n \"id\": \"app.topic\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"A1/$assetName\",\n \"isRequired\": false\n },\n {\n \"option\": [\n {\n \"label\": \"0\",\n \"value\": \"0\"\n },\n {\n \"label\": \"1\",\n \"value\": \"1\"\n }\n ],\n \"name\": \"Qos\",\n \"description\": \"The desired quality of service for the messages that have to be published. If Qos is 0, the message is delivered at most once, or it is not delivered at all. If Qos is set to 1, the message is always delivered at least once.\",\n \"id\": \"qos\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"defaultValue\": \"0\",\n \"isRequired\": true\n },\n {\n \"name\": \"Retain\",\n \"description\": \"Default retaing flag for the published messages.\",\n \"id\": \"retain\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"defaultValue\": \"false\",\n \"isRequired\": true\n },\n {\n \"option\": [\n {\n \"label\": \"Data\",\n \"value\": \"data\"\n },\n {\n \"label\": \"Control\",\n \"value\": \"control\"\n }\n ],\n \"name\": \"Kind of Message\",\n \"description\": \"Type of message to be published.\",\n \"id\": \"message.type\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"data\",\n \"isRequired\": true\n },\n {\n \"name\": \"Priority\",\n \"description\": \"Message priority. Priority level 0 (highest) should be used sparingly and reserved for messages that should be sent with the minimum latency. Default is set to 7.\",\n \"id\": \"priority\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"0\",\n \"defaultValue\": \"7\",\n \"isRequired\": true\n }\n ],\n \"name\": \"CloudPublisher\",\n \"description\": \"The CloudPublisher allows to define publishing parameters and provide a simple endpoint where the applications can attach to publish their messages.\",\n \"id\": \"org.eclipse.kura.cloud.publisher.CloudPublisher\"\n },\n \"properties\": {\n \"app.topic\": {\n \"value\": \"A1/$assetName\",\n \"type\": \"STRING\"\n },\n \"message.type\": {\n \"value\": \"data\",\n \"type\": \"STRING\"\n },\n \"qos\": {\n \"value\": 0,\n \"type\": \"INTEGER\"\n },\n \"appId\": {\n \"value\": \"W1\",\n \"type\": \"STRING\"\n },\n \"retain\": {\n \"value\": false,\n \"type\": \"BOOLEAN\"\n },\n \"priority\": {\n \"value\": 7,\n \"type\": \"INTEGER\"\n },\n \"service.factoryPid\": {\n \"value\": \"org.eclipse.kura.cloud.publisher.CloudPublisher\",\n \"type\": \"STRING\"\n },\n \"cloud.endpoint.service.pid\": {\n \"value\": \"org.eclipse.kura.cloud.CloudService\",\n \"type\": \"STRING\"\n },\n \"kura.service.pid\": {\n \"value\": \"testPub\",\n \"type\": \"STRING\"\n },\n \"service.pid\": {\n \"value\": \"org.eclipse.kura.cloud.publisher.CloudPublisher-1699623980455-20\",\n \"type\": \"STRING\"\n }\n }\n },\n {\n \"pid\": \"org.eclipse.kura.cloud.CloudService\",\n \"definition\": {\n \"ad\": [\n {\n \"option\": [\n {\n \"label\": \"Set display name as device name\",\n \"value\": \"device-name\"\n },\n {\n \"label\": \"Set display name from hostname\",\n \"value\": \"hostname\"\n },\n {\n \"label\": \"Custom\",\n \"value\": \"custom\"\n },\n {\n \"label\": \"Server defined\",\n \"value\": \"server\"\n }\n ],\n \"name\": \"Device Display-Name\",\n \"description\": \"Friendly name of the device. Device name is the common name of the device (eg: Reliagate 20-25, Raspberry Pi, etc.). Hostname will use the linux hostname utility. Custom allows for defining a unique string. Server defined relies on the remote management server to define a name.\",\n \"id\": \"device.display-name\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"device-name\",\n \"isRequired\": true\n },\n {\n \"name\": \"Device Custom-Name\",\n \"description\": \"Custom name for the device. This value is applied ONLY if device.display-name is set to \\\"Custom\\\"\",\n \"id\": \"device.custom-name\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"isRequired\": false\n },\n {\n \"name\": \"Topic Control-Prefix\",\n \"description\": \"Topic prefix for system and device management messages.\",\n \"id\": \"topic.control-prefix\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"$EDC\",\n \"isRequired\": true\n },\n {\n \"name\": \"Encode gzip\",\n \"description\": \"Compress message payloads before sending them to the remote server to reduce the network traffic.\",\n \"id\": \"encode.gzip\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"defaultValue\": \"true\",\n \"isRequired\": false\n },\n {\n \"name\": \"Republish Mqtt Birth Cert On Gps Lock\",\n \"description\": \"Whether or not to republish the MQTT Birth Certificate on GPS lock event\",\n \"id\": \"republish.mqtt.birth.cert.on.gps.lock\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"defaultValue\": \"false\",\n \"isRequired\": true\n },\n {\n \"name\": \"Republish Mqtt Birth Cert On Modem Detect\",\n \"description\": \"Whether or not to republish the MQTT Birth Certificate on modem detection event\",\n \"id\": \"republish.mqtt.birth.cert.on.modem.detect\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"defaultValue\": \"false\",\n \"isRequired\": true\n },\n {\n \"name\": \"Republish Mqtt Birth Cert On Tamper Event\",\n \"description\": \"Whether or not to republish the MQTT Birth Certificate on a tamper event. This has effect only if a TamperDetectionService is available in the framework.\",\n \"id\": \"republish.mqtt.birth.cert.on.tamper.event\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"defaultValue\": \"true\",\n \"isRequired\": true\n },\n {\n \"name\": \"Enable Default Subscriptions\",\n \"description\": \"Manages the default subscriptions to the gateway management MQTT topics. When disabled, the gateway will not be remotely manageable.\",\n \"id\": \"enable.default.subscriptions\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"defaultValue\": \"true\",\n \"isRequired\": true\n },\n {\n \"option\": [\n {\n \"label\": \"Kura Protobuf\",\n \"value\": \"kura-protobuf\"\n },\n {\n \"label\": \"Simple JSON\",\n \"value\": \"simple-json\"\n }\n ],\n \"name\": \"Payload Encoding\",\n \"description\": \"Specify the message payload encoding.\",\n \"id\": \"payload.encoding\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"kura-protobuf\",\n \"isRequired\": true\n }\n ],\n \"icon\": [\n {\n \"resource\": \"CloudService\",\n \"size\": 32\n }\n ],\n \"name\": \"CloudService\",\n \"description\": \"The CloudService allows for setting a user friendly name for the current device. It also provides the option to compress message payloads to reduce network traffic.\",\n \"id\": \"org.eclipse.kura.cloud.CloudService\"\n },\n \"properties\": {\n \"topic.control-prefix\": {\n \"value\": \"$EDC\",\n \"type\": \"STRING\"\n },\n \"republish.mqtt.birth.cert.on.tamper.event\": {\n \"value\": true,\n \"type\": \"BOOLEAN\"\n },\n \"device.custom-name\": {\n \"value\": \"Intel UP\u00b2\",\n \"type\": \"STRING\"\n },\n \"device.display-name\": {\n \"value\": \"device-name\",\n \"type\": \"STRING\"\n },\n \"payload.encoding\": {\n \"value\": \"kura-protobuf\",\n \"type\": \"STRING\"\n },\n \"republish.mqtt.birth.cert.on.modem.detect\": {\n \"value\": false,\n \"type\": \"BOOLEAN\"\n },\n \"service.factoryPid\": {\n \"value\": \"org.eclipse.kura.cloud.CloudService\",\n \"type\": \"STRING\"\n },\n \"kura.service.pid\": {\n \"value\": \"org.eclipse.kura.cloud.CloudService\",\n \"type\": \"STRING\"\n },\n \"service.pid\": {\n \"value\": \"org.eclipse.kura.cloud.CloudService-1699623980404-13\",\n \"type\": \"STRING\"\n },\n \"enable.default.subscriptions\": {\n \"value\": true,\n \"type\": \"BOOLEAN\"\n },\n \"republish.mqtt.birth.cert.on.gps.lock\": {\n \"value\": false,\n \"type\": \"BOOLEAN\"\n },\n \"encode.gzip\": {\n \"value\": true,\n \"type\": \"BOOLEAN\"\n },\n \"DataService.target\": {\n \"value\": \"(kura.service.pid=org.eclipse.kura.data.DataService)\",\n \"type\": \"STRING\"\n },\n \"kura.cloud.service.factory.pid\": {\n \"value\": \"org.eclipse.kura.core.cloud.factory.DefaultCloudServiceFactory\",\n \"type\": \"STRING\"\n }\n }\n }\n ]\n}\n
- 200 Status OK - 500 Internal Error"},{"location":"references/rest-apis/rest-cloudconnection-api/#connect-cloudendpoint","title":"Connect CloudEndpoint","text":"services/cloudconnection/v1/cloudEndpoint/connect
{\n \"cloudEndpointPid\" : \"org.eclipse.kura.cloud.CloudService\"\n}\n
"},{"location":"references/rest-apis/rest-cloudconnection-api/#responses_6","title":"Responses","text":"cloudEndpointPid
services/cloudconnection/v1/cloudEndpoint/disconnect
{\n \"cloudEndpointPid\" : \"org.eclipse.kura.cloud.CloudService\"\n}\n
"},{"location":"references/rest-apis/rest-cloudconnection-api/#responses_7","title":"Responses","text":"cloudEndpointPid
services/cloudconnection/v1/cloudEndpoint/isConnected
{\n \"cloudEndpointPid\" : \"org.eclipse.kura.cloud.CloudService\"\n}\n
"},{"location":"references/rest-apis/rest-cloudconnection-api/#responses_8","title":"Responses","text":"{\n \"connected\": false\n}\n
- 200 Status OK - 404 Wrong cloudEndpointPid
- 500 Internal Server Error"},{"location":"references/rest-apis/rest-cloudconnection-api/#put-methods","title":"PUT methods","text":""},{"location":"references/rest-apis/rest-cloudconnection-api/#update-cloudendpoint-stack-component-configurations","title":"Update CloudEndpoint stack component configurations","text":"cloudEndpoint/stackComponentPids
method.services/cloudconnection/v1/configurations
takeSnapshot
set to true o false to specify if the ConfigurationService must save a snapshot with the updated configuration.{\n \"configs\": [\n {\n \"pid\": \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\",\n \"properties\": {\n \"broker-url\": {\n \"type\": \"STRING\",\n \"value\": \"mqtt://mqtt.eclipseprojects.io:1883\"\n },\n \"topic.context.account-name\": {\n \"type\": \"STRING\",\n \"value\": \"account-name-testX2\"\n },\n \"username\": {\n \"type\": \"STRING\",\n \"value\": \"username\"\n },\n \"password\": {\n \"type\": \"PASSWORD\",\n \"value\": \"Placeholder\"\n },\n \"client-id\": {\n \"type\": \"STRING\",\n \"value\": \"\"\n },\n \"keep-alive\": {\n \"type\": \"INTEGER\",\n \"value\": 30\n },\n \"timeout\": {\n \"type\": \"INTEGER\",\n \"value\": 20\n },\n \"clean-session\": {\n \"type\": \"BOOLEAN\",\n \"value\": true\n },\n \"lwt.topic\": {\n \"type\": \"STRING\",\n \"value\": \"$EDC/#account-name/#client-id/MQTT/LWT\"\n },\n \"lwt.payload\": {\n \"type\": \"STRING\",\n \"value\": \"\"\n },\n \"lwt.qos\": {\n \"type\": \"INTEGER\",\n \"value\": 0\n },\n \"lwt.retain\": {\n \"type\": \"BOOLEAN\",\n \"value\": false\n },\n \"in-flight.persistence\": {\n \"type\": \"STRING\",\n \"value\": \"memory\"\n },\n \"protocol-version\": {\n \"type\": \"INTEGER\",\n \"value\": 4\n },\n \"SslManagerService.target\": {\n \"type\": \"STRING\",\n \"value\": \"(kura.service.pid=org.eclipse.kura.ssl.SslManagerService)\"\n }\n }\n }\n ],\n \"takeSnapshot\" : true\n}\n
"},{"location":"references/rest-apis/rest-cloudconnection-api/#responses_9","title":"Responses","text":"pid
is wrong or non existent.services/cloudconnection/v1/cloudEndpoint
{\n \"cloudConnectionFactoryPid\" : \"org.eclipse.kura.cloud.CloudService\",\n \"cloudEndpointPid\" : \"org.eclipse.kura.cloud.CloudService-1\"\n}\n
"},{"location":"references/rest-apis/rest-cloudconnection-api/#responses_10","title":"Responses","text":"cloudConnectionFactoryPid
or cloudEndpointPid
are not foundservices/cloudconnection/v1/pubSub
{\n \"pid\" : \"testPub\"\n}\n
"},{"location":"references/rest-apis/rest-cloudconnection-api/#responses_11","title":"Responses","text":"cloudConnectionFactoryPid
or cloudEndpointPid
./services/command/v1/command/
{\n //Command to be executed on gateway\n \"command\":\"printenv TextEnvVarName1\",\n\n //Service Password for command Service\n \"password\":\"s3curePassw0rd\",\n\n //String base64 encoding of a zip file to transfer to gateway\n \"zipBytes\": \"UEsDBAoACAAAAIyD1lYAA AAAAAAAAAAAAAAJACAAdGVzdGZpbGUxVVQNAAfprpRk6a6UZOmulGR1eAsAAQT1AQAABBQAAABQSwcIAAAAAAAAAAAAAAAAUEsBAgoDCgAIAAAAjIPWVgAAAAAAAAAAAAAAAAkAIAAAAAAAAAAAAKSBAAAAAHRlc3RmaWxlMVVUDQAH6a6UZOmulGTprpRkdXgLAAEE9QEAAAQUAAAAUEsFBgAAAAABAAEAVwAAAFcAAAAAAA==\",\n\n //Command argument String array\n \"arguments\":[\"arg 1\"],\n\n //Shell environment Pairs Map\n \"environmentPairs\": \n {\n \"TextEnvVarName1\":\"TextEnvVarValue1\",\n \"TextEnvVarName2\":\"TextEnvVarValue2\"\n },\n //Working directory of command to be executed\n \"workingDirectory\":\"/tmp\",\n\n}\n
"},{"location":"references/rest-apis/rest-command-api/#responses","title":"Responses","text":"{\n \"stdout\": \"Command error output is displayed in this field\",\n \"stderr\": \"Command output is displayed in this field\",\n \"exitCode\": 0,\n \"isTimeOut\": false\n}\n
/services/command/v1/command/async
{\n //Command to be executed on gateway\n \"command\":\"printenv TextEnvVarName1\",\n\n //Service Password for command Service\n \"password\":\"s3curePassw0rd\",\n\n //String base64 encoding of a zip file to transfer to gateway\n \"zipBytes\": \"UEsDBAoACAAAAIyD1lYAA AAAAAAAAAAAAAAJACAAdGVzdGZpbGUxVVQNAAfprpRk6a6UZOmulGR1eAsAAQT1AQAABBQAAABQSwcIAAAAAAAAAAAAAAAAUEsBAgoDCgAIAAAAjIPWVgAAAAAAAAAAAAAAAAkAIAAAAAAAAAAAAKSBAAAAAHRlc3RmaWxlMVVUDQAH6a6UZOmulGTprpRkdXgLAAEE9QEAAAQUAAAAUEsFBgAAAAABAAEAVwAAAFcAAAAAAA==\",\n\n //Command argument String array\n \"arguments\":[\"arg 1\"],\n\n //Shell environment Pairs Map\n \"environmentPairs\": \n {\n \"TextEnvVarName1\":\"TextEnvVarValue1\",\n \"TextEnvVarName2\":\"TextEnvVarValue2\"\n },\n //Working directory of command to be executed\n \"workingDirectory\":\"/tmp\",\n\n}\n
"},{"location":"references/rest-apis/rest-command-api/#responses_1","title":"Responses","text":"Note
Use the following command to retrieve the base64 representation of a zip file. base64 -i <filename.zip>
This page describes the configuration V1 rest APIs.
"},{"location":"references/rest-apis/rest-configuration-service-v1/#rest-apis","title":"REST APIs","text":"The Configuration Service REST APIs are exposed by the org.eclipse.kura.rest.configuration
bundle, providing the following REST APIs under the /configuration/v1
path.
/factoryComponents
configuration JSON None The method lists all the FactoryComponents Pids tracked by the ConfigurationService POST /factoryComponents
configuration JSON FactoryComponentConfiguration object Creates a new ConfigurableComponent instance by creating a new configuration from a Configuration Admin factory. The FactoryComponentConfiguration object passed as request parameter will provide all the information needed to generate the instance. It links the factory Pid to be used, the target instance Pid, the properties to be used when creating the instance, and if the request should be persisted with a snapshot DELETE /factoryComponents/{pid}?takeSnapshot={takeSnapshot}
configuration JSON pid
= A String representing the pid of the instance generated by a Factory Component that needs to deleted; takeSnapshot
= an optional (default false) boolean to specify if a new snapshot needs to be created after the delete operation For the specified Pid and optional takeSnapshot query parameter, the ConfigurationService instance will delete the corresponding ConfigurableComponent instance GET /configurableComponents
configuration JSON None Lists the tracked configurable component Pids GET /configurableComponents/configurations
configuration JSON None Lists all the component configurations of all the ConfigurableComponents tracked by the ConfigurationService GET /configurableComponents/configurations/byFilter/{filter}
configuration JSON filter
= A String representing an OSGi filter. Lists the component configurations of all the ConfigurableComponents tracked by the ConfigurationService that match the filter specified GET /configurableComponents/configurations/byPid/{pid}
configuration JSON pid
= A String representing the pid of a configurable component instance Provides the ComponentConfiguration of the ConfigurableComponent matching the specified Pid GET /configurableComponents/configurations/byPid/{pid}/_default
configuration JSON pid
= A String representing the pid of a configurable component instance Provides the default Component Configuration for the component identified by the specified Pid POST /configurableComponents/configurations/byPid/{pid}/_update
configuration JSON pid
= A String representing the pid of a configurable component instance; ComponentConfigurationUpdateRequest
= the updated configuration provided in the request body Allows to update the component configuration identified by the provided PID POST /configurableComponents/configurations/_update
configuration JSON componentConfigurations
= the list of updated configurations provided in the request body Allows to update the configuration of multiple configurable components GET /snapshots
configuration JSON None Lists all the available snapshot IDs managed by the framework GET /snapshots/{id}
configuration JSON id
= the snapshot Id Returns the content of a given snapshot tracked by the framework POST /snapshots/_write
configuration JSON None Triggers the framework to take and persist a snapshot POST /snapshots/_rollback
configuration JSON None Rollbacks the framework to the last saved snapshot if available. POST /snapshots/{id}/_rollback
configuration JSON id
= the snapshot Id Rollbacks the framework to the snapshot identified by the provided ID POST /snapshots/_upload
configuration Consumes: XML Framework snapshot in XML form provided in the request body Uploads a snapshot. The framework will update the component(s) configuration accordingly to the configurations received"},{"location":"references/rest-apis/rest-configuration-service-v1/#get-all-the-factory-components-pids","title":"Get all the factory components pids","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/factoryComponents
Response:
[\n \"org.eclipse.kura.wire.Conditional\",\n \"org.eclipse.kura.cloudconnection.raw.mqtt.publisher.RawMqttPublisher\",\n \"org.eclipse.kura.misc.cloudcat.CloudCat\",\n \"org.eclipse.kura.core.db.H2DbServer\",\n \"org.eclipse.kura.wire.Fifo\",\n \"org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint\",\n \"org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl\",\n \"org.eclipse.kura.cloud.publisher.CloudPublisher\",\n \"org.eclipse.kura.core.db.H2DbService\",\n \"org.eclipse.kura.wire.CloudSubscriber\",\n \"org.eclipse.kura.wire.RegexFilter\",\n \"org.eclipse.kura.wire.Logger\",\n \"org.eclipse.kura.wire.Timer\",\n \"com.eurotech.framework.log.manager.LogManager\",\n \"com.eurotech.framework.log.journald.wire.JournaldWireComponent\",\n \"org.eclipse.kura.cloudconnection.raw.mqtt.subscriber.RawMqttSubscriber\",\n \"org.eclipse.kura.cloud.subscriber.CloudSubscriber\",\n \"org.eclipse.kura.ssl.SslManagerService\",\n \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\",\n \"com.eurotech.framework.log.journald.JournaldLogReader\",\n \"org.eclipse.kura.provisioning.ProvisioningService\",\n \"org.eclipse.kura.wire.CloudPublisher\",\n \"org.eclipse.kura.wire.H2DbWireRecordFilter\",\n \"org.eclipse.kura.cloud.CloudService\",\n \"org.eclipse.kura.data.DataService\",\n \"org.eclipse.kura.wire.H2DbWireRecordStore\",\n \"org.eclipse.kura.wire.Join\",\n \"com.eurotech.framework.log.publisher.LogPublisher\"\n]\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#create-component-from-factory","title":"Create component from factory","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/factoryComponents
Request body:
{\n \"factoryPid\": \"org.eclipse.kura.core.db.H2DbServer\",\n \"pid\": \"myH2DbServer\",\n \"properties\" : [],\n \"takeSnapshot\" : false\n}\n
The request must be provided with the following elements:
Request: URL - https://<gateway-ip>/services/configuration/v1/factoryComponents/{pid}?takeSnapshot={takeSnapshot}
Request: URL - https://<gateway-ip>/services/configuration/v1/configurableComponents
Response:
[\n \"org.eclipse.kura.clock.ClockService\",\n \"org.eclipse.kura.net.admin.NetworkConfigurationService\",\n \"org.eclipse.kura.position.PositionService\",\n \"com.eurotech.framework.internal.ansible.provider.AnsibleServiceImpl\",\n \"org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl\",\n \"com.eurotech.framework.internal.ansible.cloud.AnsibleActivityHandler\",\n \"default.diagnostic.publisher\",\n \"org.eclipse.kura.net.admin.FirewallConfigurationService\",\n \"com.eurotech.framework.internal.fail2ban.Fail2BanConfigurator\",\n \"default.log.publisher\",\n \"org.eclipse.kura.wire.graph.WireGraphService\",\n \"com.eurotech.framework.internal.floodingprotection.FloodingProtectionConfigurator\",\n \"org.eclipse.kura.ssl.SslManagerService\",\n \"org.eclipse.kura.http.server.manager.HttpService\",\n \"org.eclipse.kura.cloud.app.command.CommandCloudApp\",\n \"default.ping.publisher\",\n \"org.eclipse.kura.db.H2DbService\",\n \"com.eurotech.framework.diagnostics.DiagnosticsService\",\n \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\",\n \"org.eclipse.kura.deployment.agent\",\n \"DMKeystore\",\n \"LogReaderJournald\",\n \"default.alert.publisher\",\n \"org.eclipse.kura.core.deployment.CloudDeploymentHandlerV2\",\n \"HttpsKeystore\",\n \"com.eurotech.framework.security.aide.AideTamperDetectionServiceConfigurator\",\n \"org.eclipse.kura.provisioning.ProvisioningService\",\n \"LogManagerAuth\",\n \"com.eurotech.framework.security.journald.fss.FssTamperDetectionServiceConfigurator\",\n \"org.eclipse.kura.watchdog.WatchdogService\",\n \"org.eclipse.kura.cloud.CloudService\",\n \"LogManagerActivity\",\n \"org.eclipse.kura.data.DataService\",\n \"LogManagerDefault\",\n \"org.eclipse.kura.web.Console\",\n \"SSLKeystore\",\n \"com.eurotech.framework.net.vpn.client.VpnClient\",\n \"org.eclipse.kura.internal.rest.provider.RestService\",\n \"com.eurotech.framework.reboot.RebootService\"\n]\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#lists-all-the-component-configurations-of-all-the-configurablecomponents","title":"Lists all the component configurations of all the ConfigurableComponents","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/configurableComponents/configurations
Response:
[\n {\n \"pid\": \"org.eclipse.kura.clock.ClockService\",\n \"definition\": {\n \"ad\": [\n {\n \"option\": [],\n \"name\": \"enabled\",\n \"description\": \"Whether or not to enable the ClockService\",\n \"id\": \"enabled\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"_default\": \"true\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.set.hwclock\",\n \"description\": \"Whether or not to sync the system hardware clock after the system time gets set\",\n \"id\": \"clock.set.hwclock\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"_default\": \"true\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [\n {\n \"label\": \"java-ntp\",\n \"value\": \"java-ntp\",\n \"otherAttributes\": {}\n },\n {\n \"label\": \"ntpd\",\n \"value\": \"ntpd\",\n \"otherAttributes\": {}\n },\n {\n \"label\": \"chrony-advanced\",\n \"value\": \"chrony-advanced\",\n \"otherAttributes\": {}\n }\n ],\n \"name\": \"clock.provider\",\n \"description\": \"Source for setting the system clock. Verify the availabiliy of the selected provider before activate it.\",\n \"id\": \"clock.provider\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"java-ntp\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.host\",\n \"description\": \"The hostname that provides the system time via NTP\",\n \"id\": \"clock.ntp.host\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"0.pool.ntp.org\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.port\",\n \"description\": \"The port number that provides the system time via NTP\",\n \"id\": \"clock.ntp.port\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1\",\n \"max\": \"65535\",\n \"_default\": \"123\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.timeout\",\n \"description\": \"The NTP timeout in milliseconds\",\n \"id\": \"clock.ntp.timeout\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1000\",\n \"_default\": \"10000\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.max-retry\",\n \"description\": \"The maximum number of retries for the initial synchronization (with interval clock.ntp.retry.interval). If set to 0 the service will retry forever.\",\n \"id\": \"clock.ntp.max-retry\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"0\",\n \"_default\": \"0\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.retry.interval\",\n \"description\": \"When sync fails, interval in seconds between each retry.\",\n \"id\": \"clock.ntp.retry.interval\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1\",\n \"_default\": \"5\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.refresh-interval\",\n \"description\": \"Whether or not to sync the clock and if so, the frequency in seconds. If less than zero - no update, if equal to zero - sync once at startup, if greater than zero - the frequency in seconds to perform a new clock sync\",\n \"id\": \"clock.ntp.refresh-interval\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"_default\": \"3600\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"RTC File Name\",\n \"description\": \"The RTC File Name. It defaults to /dev/rtc0. This option is not used if chrony-advanced option is selected in clock.provider.\",\n \"id\": \"rtc.filename\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"/dev/rtc0\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"Chrony Configuration\",\n \"description\": \"Chrony configuration file.|TextArea\",\n \"id\": \"chrony.advanced.config\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"required\": false,\n \"otherAttributes\": {}\n }\n ],\n \"icon\": [\n {\n \"resource\": \"ClockService\",\n \"size\": 32,\n \"otherAttributes\": {}\n }\n ],\n \"name\": \"ClockService\",\n \"description\": \"ClockService Configuration\",\n \"id\": \"org.eclipse.kura.clock.ClockService\",\n \"otherAttributes\": {}\n },\n \"properties\": {\n \"clock.ntp.host\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"0.pool.ntp.org\"\n },\n \"clock.ntp.max-retry\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 0\n },\n \"clock.set.hwclock\": {\n \"array\": false,\n \"type\": \"Boolean\",\n \"value\": true\n },\n \"clock.ntp.timeout\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 10000\n },\n \"enabled\": {\n \"array\": false,\n \"type\": \"Boolean\",\n \"value\": false\n },\n \"clock.ntp.retry.interval\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 5\n },\n \"kura.service.pid\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"org.eclipse.kura.clock.ClockService\"\n },\n \"service.pid\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"org.eclipse.kura.clock.ClockService\"\n },\n \"clock.ntp.port\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 123\n },\n \"clock.provider\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"java-ntp\"\n },\n \"clock.ntp.refresh-interval\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 3600\n },\n \"rtc.filename\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"/dev/rtc1\"\n },\n \"chrony.advanced.config\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"\"\n }\n }\n },\n ...\n]\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#list-the-configurations-of-all-the-configurablecomponents-that-match-a-filter","title":"List the configurations of all the ConfigurableComponents that match a filter","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/configurableComponents/configurations/byFilter/(service.pid=org.eclipse.kura.clock.ClockService)
Response:
[\n {\n \"pid\": \"org.eclipse.kura.clock.ClockService\",\n \"definition\": {\n \"ad\": [\n {\n \"option\": [],\n \"name\": \"enabled\",\n \"description\": \"Whether or not to enable the ClockService\",\n \"id\": \"enabled\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"_default\": \"true\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.set.hwclock\",\n \"description\": \"Whether or not to sync the system hardware clock after the system time gets set\",\n \"id\": \"clock.set.hwclock\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"_default\": \"true\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [\n {\n \"label\": \"java-ntp\",\n \"value\": \"java-ntp\",\n \"otherAttributes\": {}\n },\n {\n \"label\": \"ntpd\",\n \"value\": \"ntpd\",\n \"otherAttributes\": {}\n },\n {\n \"label\": \"chrony-advanced\",\n \"value\": \"chrony-advanced\",\n \"otherAttributes\": {}\n }\n ],\n \"name\": \"clock.provider\",\n \"description\": \"Source for setting the system clock. Verify the availabiliy of the selected provider before activate it.\",\n \"id\": \"clock.provider\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"java-ntp\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.host\",\n \"description\": \"The hostname that provides the system time via NTP\",\n \"id\": \"clock.ntp.host\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"0.pool.ntp.org\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.port\",\n \"description\": \"The port number that provides the system time via NTP\",\n \"id\": \"clock.ntp.port\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1\",\n \"max\": \"65535\",\n \"_default\": \"123\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.timeout\",\n \"description\": \"The NTP timeout in milliseconds\",\n \"id\": \"clock.ntp.timeout\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1000\",\n \"_default\": \"10000\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.max-retry\",\n \"description\": \"The maximum number of retries for the initial synchronization (with interval clock.ntp.retry.interval). If set to 0 the service will retry forever.\",\n \"id\": \"clock.ntp.max-retry\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"0\",\n \"_default\": \"0\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.retry.interval\",\n \"description\": \"When sync fails, interval in seconds between each retry.\",\n \"id\": \"clock.ntp.retry.interval\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1\",\n \"_default\": \"5\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.refresh-interval\",\n \"description\": \"Whether or not to sync the clock and if so, the frequency in seconds. If less than zero - no update, if equal to zero - sync once at startup, if greater than zero - the frequency in seconds to perform a new clock sync\",\n \"id\": \"clock.ntp.refresh-interval\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"_default\": \"3600\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"RTC File Name\",\n \"description\": \"The RTC File Name. It defaults to /dev/rtc0. This option is not used if chrony-advanced option is selected in clock.provider.\",\n \"id\": \"rtc.filename\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"/dev/rtc0\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"Chrony Configuration\",\n \"description\": \"Chrony configuration file.|TextArea\",\n \"id\": \"chrony.advanced.config\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"required\": false,\n \"otherAttributes\": {}\n }\n ],\n \"icon\": [\n {\n \"resource\": \"ClockService\",\n \"size\": 32,\n \"otherAttributes\": {}\n }\n ],\n \"name\": \"ClockService\",\n \"description\": \"ClockService Configuration\",\n \"id\": \"org.eclipse.kura.clock.ClockService\",\n \"otherAttributes\": {}\n },\n \"properties\": {\n \"clock.ntp.host\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"0.pool.ntp.org\"\n },\n \"clock.ntp.max-retry\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 0\n },\n \"clock.set.hwclock\": {\n \"array\": false,\n \"type\": \"Boolean\",\n \"value\": true\n },\n \"clock.ntp.timeout\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 10000\n },\n \"enabled\": {\n \"array\": false,\n \"type\": \"Boolean\",\n \"value\": false\n },\n \"clock.ntp.retry.interval\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 5\n },\n \"kura.service.pid\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"org.eclipse.kura.clock.ClockService\"\n },\n \"service.pid\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"org.eclipse.kura.clock.ClockService\"\n },\n \"clock.ntp.port\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 123\n },\n \"clock.provider\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"java-ntp\"\n },\n \"clock.ntp.refresh-interval\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 3600\n },\n \"rtc.filename\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"/dev/rtc1\"\n },\n \"chrony.advanced.config\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"\"\n }\n }\n }\n]\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#get-the-configuration-of-the-configurablecomponent-matching-a-pid","title":"Get the configuration of the ConfigurableComponent matching a pid","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/configurableComponents/configurations/byPid/org.eclipse.kura.clock.ClockService
Response:
{\n \"pid\": \"org.eclipse.kura.clock.ClockService\",\n \"definition\": {\n \"ad\": [\n {\n \"option\": [],\n \"name\": \"enabled\",\n \"description\": \"Whether or not to enable the ClockService\",\n \"id\": \"enabled\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"_default\": \"true\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.set.hwclock\",\n \"description\": \"Whether or not to sync the system hardware clock after the system time gets set\",\n \"id\": \"clock.set.hwclock\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"_default\": \"true\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [\n {\n \"label\": \"java-ntp\",\n \"value\": \"java-ntp\",\n \"otherAttributes\": {}\n },\n {\n \"label\": \"ntpd\",\n \"value\": \"ntpd\",\n \"otherAttributes\": {}\n },\n {\n \"label\": \"chrony-advanced\",\n \"value\": \"chrony-advanced\",\n \"otherAttributes\": {}\n }\n ],\n \"name\": \"clock.provider\",\n \"description\": \"Source for setting the system clock. Verify the availabiliy of the selected provider before activate it.\",\n \"id\": \"clock.provider\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"java-ntp\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.host\",\n \"description\": \"The hostname that provides the system time via NTP\",\n \"id\": \"clock.ntp.host\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"0.pool.ntp.org\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.port\",\n \"description\": \"The port number that provides the system time via NTP\",\n \"id\": \"clock.ntp.port\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1\",\n \"max\": \"65535\",\n \"_default\": \"123\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.timeout\",\n \"description\": \"The NTP timeout in milliseconds\",\n \"id\": \"clock.ntp.timeout\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1000\",\n \"_default\": \"10000\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.max-retry\",\n \"description\": \"The maximum number of retries for the initial synchronization (with interval clock.ntp.retry.interval). If set to 0 the service will retry forever.\",\n \"id\": \"clock.ntp.max-retry\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"0\",\n \"_default\": \"0\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.retry.interval\",\n \"description\": \"When sync fails, interval in seconds between each retry.\",\n \"id\": \"clock.ntp.retry.interval\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1\",\n \"_default\": \"5\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.refresh-interval\",\n \"description\": \"Whether or not to sync the clock and if so, the frequency in seconds. If less than zero - no update, if equal to zero - sync once at startup, if greater than zero - the frequency in seconds to perform a new clock sync\",\n \"id\": \"clock.ntp.refresh-interval\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"_default\": \"3600\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"RTC File Name\",\n \"description\": \"The RTC File Name. It defaults to /dev/rtc0. This option is not used if chrony-advanced option is selected in clock.provider.\",\n \"id\": \"rtc.filename\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"/dev/rtc0\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"Chrony Configuration\",\n \"description\": \"Chrony configuration file.|TextArea\",\n \"id\": \"chrony.advanced.config\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"required\": false,\n \"otherAttributes\": {}\n }\n ],\n \"icon\": [\n {\n \"resource\": \"ClockService\",\n \"size\": 32,\n \"otherAttributes\": {}\n }\n ],\n \"name\": \"ClockService\",\n \"description\": \"ClockService Configuration\",\n \"id\": \"org.eclipse.kura.clock.ClockService\",\n \"otherAttributes\": {}\n },\n \"properties\": {\n \"clock.ntp.host\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"0.pool.ntp.org\"\n },\n \"clock.ntp.max-retry\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 0\n },\n \"clock.set.hwclock\": {\n \"array\": false,\n \"type\": \"Boolean\",\n \"value\": true\n },\n \"clock.ntp.timeout\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 10000\n },\n \"enabled\": {\n \"array\": false,\n \"type\": \"Boolean\",\n \"value\": false\n },\n \"clock.ntp.retry.interval\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 5\n },\n \"kura.service.pid\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"org.eclipse.kura.clock.ClockService\"\n },\n \"service.pid\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"org.eclipse.kura.clock.ClockService\"\n },\n \"clock.ntp.port\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 123\n },\n \"clock.provider\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"java-ntp\"\n },\n \"clock.ntp.refresh-interval\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 3600\n },\n \"rtc.filename\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"/dev/rtc1\"\n },\n \"chrony.advanced.config\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"\"\n }\n }\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#get-the-default-configuration-of-the-configurablecomponent-matching-a-pid","title":"Get the default configuration of the ConfigurableComponent matching a pid","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/configurableComponents/configurations/byPid/org.eclipse.kura.clock.ClockService/_default
Response:
{\n \"pid\": \"org.eclipse.kura.clock.ClockService\",\n \"definition\": {\n \"ad\": [\n {\n \"option\": [],\n \"name\": \"enabled\",\n \"description\": \"Whether or not to enable the ClockService\",\n \"id\": \"enabled\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"_default\": \"true\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.set.hwclock\",\n \"description\": \"Whether or not to sync the system hardware clock after the system time gets set\",\n \"id\": \"clock.set.hwclock\",\n \"type\": \"BOOLEAN\",\n \"cardinality\": 0,\n \"_default\": \"true\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [\n {\n \"label\": \"java-ntp\",\n \"value\": \"java-ntp\",\n \"otherAttributes\": {}\n },\n {\n \"label\": \"ntpd\",\n \"value\": \"ntpd\",\n \"otherAttributes\": {}\n },\n {\n \"label\": \"chrony-advanced\",\n \"value\": \"chrony-advanced\",\n \"otherAttributes\": {}\n }\n ],\n \"name\": \"clock.provider\",\n \"description\": \"Source for setting the system clock. Verify the availabiliy of the selected provider before activate it.\",\n \"id\": \"clock.provider\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"java-ntp\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.host\",\n \"description\": \"The hostname that provides the system time via NTP\",\n \"id\": \"clock.ntp.host\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"0.pool.ntp.org\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.port\",\n \"description\": \"The port number that provides the system time via NTP\",\n \"id\": \"clock.ntp.port\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1\",\n \"max\": \"65535\",\n \"_default\": \"123\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.timeout\",\n \"description\": \"The NTP timeout in milliseconds\",\n \"id\": \"clock.ntp.timeout\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1000\",\n \"_default\": \"10000\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.max-retry\",\n \"description\": \"The maximum number of retries for the initial synchronization (with interval clock.ntp.retry.interval). If set to 0 the service will retry forever.\",\n \"id\": \"clock.ntp.max-retry\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"0\",\n \"_default\": \"0\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.retry.interval\",\n \"description\": \"When sync fails, interval in seconds between each retry.\",\n \"id\": \"clock.ntp.retry.interval\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"min\": \"1\",\n \"_default\": \"5\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"clock.ntp.refresh-interval\",\n \"description\": \"Whether or not to sync the clock and if so, the frequency in seconds. If less than zero - no update, if equal to zero - sync once at startup, if greater than zero - the frequency in seconds to perform a new clock sync\",\n \"id\": \"clock.ntp.refresh-interval\",\n \"type\": \"INTEGER\",\n \"cardinality\": 0,\n \"_default\": \"3600\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"RTC File Name\",\n \"description\": \"The RTC File Name. It defaults to /dev/rtc0. This option is not used if chrony-advanced option is selected in clock.provider.\",\n \"id\": \"rtc.filename\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"_default\": \"/dev/rtc0\",\n \"required\": true,\n \"otherAttributes\": {}\n },\n {\n \"option\": [],\n \"name\": \"Chrony Configuration\",\n \"description\": \"Chrony configuration file.|TextArea\",\n \"id\": \"chrony.advanced.config\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"required\": false,\n \"otherAttributes\": {}\n }\n ],\n \"icon\": [\n {\n \"resource\": \"ClockService\",\n \"size\": 32,\n \"otherAttributes\": {}\n }\n ],\n \"name\": \"ClockService\",\n \"description\": \"ClockService Configuration\",\n \"id\": \"org.eclipse.kura.clock.ClockService\",\n \"otherAttributes\": {}\n },\n \"properties\": {\n \"clock.ntp.host\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"0.pool.ntp.org\"\n },\n \"clock.provider\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"java-ntp\"\n },\n \"clock.ntp.port\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 123\n },\n \"clock.ntp.max-retry\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 0\n },\n \"clock.ntp.refresh-interval\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 3600\n },\n \"rtc.filename\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"/dev/rtc0\"\n },\n \"clock.set.hwclock\": {\n \"array\": false,\n \"type\": \"Boolean\",\n \"value\": true\n },\n \"enabled\": {\n \"array\": false,\n \"type\": \"Boolean\",\n \"value\": true\n },\n \"clock.ntp.timeout\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 10000\n },\n \"clock.ntp.retry.interval\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 5\n }\n }\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#update-the-component-configuration-identified-matching-a-pid","title":"Update the component configuration identified matching a pid","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/configurableComponents/configurations/byPid/org.eclipse.kura.clock.ClockService/_update
Request body:
{\n \"takeSnapshot\":true,\n \"componentConfigurationRequest\": {\n \"properties\": {\n \"enabled\": {\n \"type\": \"boolean\",\n \"value\": false,\n \"array\": false\n }\n }\n }\n}\n
Warning
Every service may need a different set of parameters and combination of them to reach the desired result. For the NetworkAdminService, for example, the following configuration is required to disable a specific network interface (enp2s0) and prevent re-enabling at reboot. Please verify offline the REST APIs executed and the different deploying scenarios before distributing updates to the fleet of devices.
{\n \"takeSnapshot\":true,\n \"componentConfigurationRequest\": {\n \"properties\": {\n \"net.interface.enp2s0.config.ip4.status\": {\n \"type\": \"string\",\n \"value\": \"netIPv4StatusDisabled\",\n \"array\": false\n },\n \"net.interface.enp2s0.config.autoconnect\": {\n \"type\": \"boolean\",\n \"value\": false,\n \"array\": false\n }\n }\n }\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#update-the-configuration-of-multiple-configurable-components","title":"Update the configuration of multiple configurable components","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/configurableComponents/configurations/_update
Request body:
{\n \"takeSnapshot\": true,\n \"componentConfigurations\": [\n {\n \"pid\": \"org.eclipse.kura.clock.ClockService\",\n \"properties\": {\n \"enabled\": {\n \"type\": \"boolean\",\n \"value\": false,\n \"array\": false\n }\n }\n }\n ]\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#list-all-the-available-snapshot-ids","title":"List all the available snapshot IDs","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/snapshots
Response:
[\n 0,\n 1630930775789,\n 1630930776355,\n 1630930776839,\n 1630930797402,\n 1630930805305\n]\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#get-the-content-of-a-given-snapshot","title":"Get the content of a given snapshot","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/snapshots/{id}
Response:
[\n {\n \"pid\": \"org.eclipse.kura.clock.ClockService\",\n \"properties\": {\n \"clock.ntp.host\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"0.pool.ntp.org\"\n },\n \"clock.ntp.port\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 123\n },\n \"clock.provider\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"java-ntp\"\n },\n \"clock.ntp.max-retry\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 0\n },\n \"clock.ntp.refresh-interval\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 3600\n },\n \"rtc.filename\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"/dev/rtc1\"\n },\n \"clock.set.hwclock\": {\n \"array\": false,\n \"type\": \"Boolean\",\n \"value\": true\n },\n \"clock.ntp.timeout\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 10000\n },\n \"enabled\": {\n \"array\": false,\n \"type\": \"Boolean\",\n \"value\": true\n },\n \"clock.ntp.retry.interval\": {\n \"array\": false,\n \"type\": \"Integer\",\n \"value\": 5\n },\n \"kura.service.pid\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"org.eclipse.kura.clock.ClockService\"\n },\n \"service.pid\": {\n \"array\": false,\n \"type\": \"String\",\n \"value\": \"org.eclipse.kura.clock.ClockService\"\n }\n }\n },\n ...\n]\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#trigger-the-framework-to-take-and-persist-a-snapshot","title":"Trigger the framework to take and persist a snapshot","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/snapshots/_write
Response:
1631095409516\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#rollbacks-to-the-snapshot-identified-by-the-provided-id","title":"Rollbacks to the snapshot identified by the provided ID","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/snapshots/_rollback
Response:
1631093011618\n
"},{"location":"references/rest-apis/rest-configuration-service-v1/#upload-a-snapshot-as-xml","title":"Upload a snapshot as XML","text":"Request: URL - https://<gateway-ip>/services/configuration/v1/snapshots/_upload
Request body:
<?xml version=\"1.0\" encoding=\"UTF-8\"?><esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n <esf:configuration pid=\"org.eclipse.kura.clock.ClockService\">\n <esf:properties>\n <esf:property array=\"false\" encrypted=\"false\" name=\"clock.ntp.host\" type=\"String\">\n <esf:value>0.pool.ntp.org</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"clock.ntp.port\" type=\"Integer\">\n <esf:value>123</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"clock.provider\" type=\"String\">\n <esf:value>java-ntp</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"clock.ntp.max-retry\" type=\"Integer\">\n <esf:value>0</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"clock.ntp.refresh-interval\" type=\"Integer\">\n <esf:value>3600</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"rtc.filename\" type=\"String\">\n <esf:value>/dev/rtc1</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"clock.set.hwclock\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"clock.ntp.timeout\" type=\"Integer\">\n <esf:value>10000</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"enabled\" type=\"Boolean\">\n <esf:value>true</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"clock.ntp.retry.interval\" type=\"Integer\">\n <esf:value>5</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"kura.service.pid\" type=\"String\">\n <esf:value>org.eclipse.kura.clock.ClockService</esf:value>\n </esf:property>\n <esf:property array=\"false\" encrypted=\"false\" name=\"service.pid\" type=\"String\">\n <esf:value>org.eclipse.kura.clock.ClockService</esf:value>\n </esf:property>\n </esf:properties>\n </esf:configuration>\n</esf:configurations>\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/","title":"Configuration V2 REST APIs and CONF-V2 Request Handler","text":"This page describes the CONF-V2 request handler and configuration/v2
rest APIs. Accessing the REST APIs requires to use an identity with the rest.configuration
permission assigned.
/services/configuration/v2/snapshots
/services/configuration/v2/factoryComponents
/services/configuration/v2/factoryComponents
create:$pid
for component creation operations, where $pid
is the pid of the instance, and snapshot
, for the snapshot creation operation. In case of an unexpected failure, a generic error response will be returned.response body :
Variants:
/services/configuration/v2/factoryComponents/byPid
delete:$pid
for component delete operations, where $pid
is the pid of the instance, and snapshot
, for the snapshot creation operation. In case of an unexpected failure, a generic error response will be returned.response body :
Variants:
/services/configuration/v2/factoryComponents/ocd
pid
property of the received configurations will report the factory pid, the ocd
field will contain the definition, the properties
field will not be present./services/configuration/v2/factoryComponents/ocd/byFactoryPid
pid
property of the received configurations will report the factory pid, the ocd
field will contain the definition, the properties
field will not be present. If the OCD for a given factory pid cannot be found, it will not be included in the result./services/configuration/v2/configurableComponents
/services/configuration/v2/configurableComponents/pidsWithFactory
/services/configuration/v2/configurableComponents/configurations
pid
, ocd
and properties
./services/configuration/v2/configurableComponents/configurations/byPid
pid
, ocd
and properties
./services/configuration/v2/configurableComponents/configurations/byPid/_default
pid
, ocd
and properties
./services/configuration/v2/configurableComponents/configurations/_update
update:$pid
for component update operations, where $pid
is the pid of the instance, and snapshot
, for the snapshot creation operation. In case of an unexpected failure, a generic error response will be returned.response body :
Variants:
/services/configuration/v2/snapshots/_write
/services/configuration/v2/snapshots/_rollback
/services/configuration/v2/snapshots/byId/_rollback
Represents a set of pids with the corresponding factory pid. Properties:
components: array
The set of pids and factory pids
array elements: object
The pid and factory pid Properties:
pid: string
The component pid.
string
{\n \"components\": [\n {\n \"factoryPid\": \"org.eclipse.kura.core.db.H2DbService\",\n \"pid\": \"org.eclipse.kura.db.H2DbService\"\n },\n {\n \"factoryPid\": \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\",\n \"pid\": \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\"\n },\n {\n \"pid\": \"org.eclipse.kura.web.Console\"\n }\n ]\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#snapshotidset","title":"SnapshotIdSet","text":"An object decribing a set of configuration snapshot ids Properties:
array
The set of snapshot ids.number
A snapshot id.{\n \"ids\": [\n 0,\n 1638438049921,\n 1638438146960,\n 1638439710944,\n 1638439717931,\n 1638439734077,\n 1638439767252,\n 1638521986953,\n 1638521993692,\n 1638522572822\n ]\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#propertytype","title":"PropertyType","text":"A string that describes the type of a configuration property. * Possible values * STRING
* LONG
* DOUBLE
* FLOAT
* INTEGER
* BYTE
* CHAR
* BOOLEAN
* SHORT
* PASSWORD
\"STRING\"\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#configurationproperty","title":"ConfigurationProperty","text":"An object describing a configuration property. Properties:
string (enumerated)
variant
optional In requests, this field can be omitted or set to null
to assign the null
value to a non required configuration property. Describes the property value. The value type depends on the type property. Variants:
LONG
, DOUBLE
, FLOAT
, INTEGER
, BYTE
or SHORT
and the property does not represent an array.STRING
, PASSWORD
or CHAR
and the property is not an array. In case of CHAR
type, the value must have a length of 1.BOOLEAN
and the property is not an arrayLONG
, DOUBLE
, FLOAT
, INTEGER
, BYTE
or SHORT
and the property represents an array.number
The property values as numbers.STRING
, PASSWORD
or CHAR
and the property is an array.string
The property values as strings. In case of CHAR
type, the values must have a length of 1.BOOLEAN
and the property is an arraybool
The property values as booleans.{\n \"type\": \"STRING\",\n \"value\": \"foo\"\n}\n
{\n \"type\": \"STRING\",\n \"value\": [\n \"foo\",\n \"bar\"\n ]\n}\n
{\n \"type\": \"INTEGER\",\n \"value\": 12\n}\n
{\n \"type\": \"LONG\",\n \"value\": [\n 1,\n 2,\n 3,\n 4\n ]\n}\n
{\n \"type\": \"PASSWORD\",\n \"value\": \"myPassword\"\n}\n
{\n \"type\": \"PASSWORD\",\n \"value\": [\n \"my\",\n \"password\",\n \"array\"\n ]\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#configurationproperties","title":"ConfigurationProperties","text":"An object representing a set of configuration properties. The members of this object represent configuration property, the member names represent the configuration property ids. This object can have a variable number of members. Properties:
object
{\n \"KeystoreService.target\": {\n \"type\": \"STRING\",\n \"value\": \"(kura.service.pid=HttpsKeystore)\"\n },\n \"https.client.auth.ports\": {\n \"type\": \"INTEGER\",\n \"value\": [\n 4443\n ]\n },\n \"https.client.revocation.soft.fail\": {\n \"type\": \"BOOLEAN\",\n \"value\": false\n },\n \"https.ports\": {\n \"type\": \"INTEGER\",\n \"value\": [\n 443\n ]\n },\n \"https.revocation.check.enabled\": {\n \"type\": \"BOOLEAN\",\n \"value\": false\n },\n \"kura.service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.http.server.manager.HttpService\"\n },\n \"service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.http.server.manager.HttpService\"\n },\n \"ssl.revocation.mode\": {\n \"type\": \"STRING\",\n \"value\": \"PREFER_OCSP\"\n }\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#option","title":"Option","text":"An object describing an allowed element for a multi choiche field. Properties:
string
string
The option value encoded as a string.{\n \"label\": \"Value 1\",\n \"value\": \"1\"\n}\n
{\n \"value\": \"foo\"\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#attributedefinition","title":"AttributeDefinition","text":"A descriptor of a configuration property. Properties:
string
The id of the attribute definition. This field corresponds to the configuration property name.string (enumerated)
string
string
number
An integer describing the property cardinality. If the value is 0, then the property is a singleton value (not an array), if it is > 0, then the configuration property is an array and this property specifies the maximum allowed array length.string
string
bool
Specifies whether the configuration parameter is required or not.string
array
object
{\n \"defaultValue\": \"false\",\n \"description\": \"Specifies whether the DB server is enabled or not.\",\n \"id\": \"db.server.enabled\",\n \"isRequired\": true,\n \"name\": \"db.server.enabled\",\n \"type\": \"BOOLEAN\"\n}\n
{\n \"defaultValue\": \"TCP\",\n \"description\": \"Specifies the server type, see http://www.h2database.com/javadoc/org/h2/tools/Server.html for more details.\",\n \"id\": \"db.server.type\",\n \"isRequired\": true,\n \"name\": \"db.server.type\",\n \"option\": [\n {\n \"label\": \"WEB\",\n \"value\": \"WEB\"\n },\n {\n \"label\": \"TCP\",\n \"value\": \"TCP\"\n },\n {\n \"label\": \"PG\",\n \"value\": \"PG\"\n }\n ],\n \"type\": \"STRING\"\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#objectclassdefinition","title":"ObjectClassDefinition","text":"Provides some metadata information about a component configuration. Properties:
array
The metadata about the configuration properties.object
array
optional Can be missing if the OCD does not define icons. A list of icons that visually represent the configuration.
object
Properties:
string
An identifier of the icon image resource.number
The icon width and height in pixels.string
A user friendly name for the component configuration.string
A user friendly description of the component configuration.string
An identifier of the component configuration.{\n \"ad\": [\n {\n \"defaultValue\": \"false\",\n \"description\": \"The WatchdogService monitors CriticalComponents and reboots the system if one of them hangs. Once enabled the WatchdogService starts refreshing the watchdog device, which will reset the system if WatchdogService hangs.\",\n \"id\": \"enabled\",\n \"isRequired\": true,\n \"name\": \"Watchdog enable\",\n \"type\": \"BOOLEAN\"\n },\n {\n \"defaultValue\": \"10000\",\n \"description\": \"WatchdogService's refresh interval in ms of the Watchdog device. The value can be set between 1 and 60 seconds and should not be set to a value greater or equal to the Watchdog device's timeout value\",\n \"id\": \"pingInterval\",\n \"isRequired\": true,\n \"max\": \"60000\",\n \"name\": \"Watchdog refresh interval\",\n \"type\": \"INTEGER\"\n },\n {\n \"defaultValue\": \"/dev/watchdog\",\n \"description\": \"Watchdog device path e.g. /dev/watchdog.\",\n \"id\": \"watchdogDevice\",\n \"isRequired\": true,\n \"name\": \"Watchdog device path\",\n \"type\": \"STRING\"\n },\n {\n \"defaultValue\": \"/opt/eclipse/kura/data/kura-reboot-cause\",\n \"description\": \"The path for the file that will contain the reboot cause information.\",\n \"id\": \"rebootCauseFilePath\",\n \"isRequired\": true,\n \"name\": \"Reboot Cause File Path\",\n \"type\": \"STRING\"\n }\n ],\n \"description\": \"The WatchdogService handles the hardware watchdog of the platform. The parameter define the ping periodicity of the hardware watchdog to ensure it does not reboot. The WatchdogService will reset the watchdog timeout, can disable it (where supported) with the Magic Character, but cannot set the refresh rate of a watchdog device.\",\n \"icon\": [\n {\n \"resource\": \"WatchdogService\",\n \"size\": 32\n }\n ],\n \"id\": \"org.eclipse.kura.watchdog.WatchdogService\",\n \"name\": \"WatchdogService\"\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#componentconfiguration","title":"ComponentConfiguration","text":"Describes a component configuration. Properties:
string
The identifier of this configuration.object
object
{\n \"definition\": {\n \"ad\": [\n {\n \"cardinality\": 3,\n \"description\": \"If set to a non empty list, REST API access will be allowed only on the specified ports. If set to an empty list, access will be allowed on all ports. Please make sure that the allowed ports are open in HttpService and Firewall configuration.\",\n \"id\": \"allowed.ports\",\n \"isRequired\": false,\n \"max\": \"65535\",\n \"min\": \"1\",\n \"name\": \"Allowed ports\",\n \"type\": \"INTEGER\"\n }\n ],\n \"description\": \"This service allows to configure settings related to Kura REST APIs\",\n \"id\": \"org.eclipse.kura.internal.rest.provider.RestService\",\n \"name\": \"RestService\"\n },\n \"pid\": \"org.eclipse.kura.internal.rest.provider.RestService\",\n \"properties\": {\n \"kura.service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.internal.rest.provider.RestService\"\n },\n \"service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.internal.rest.provider.RestService\"\n }\n }\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#componentconfigurationlist","title":"ComponentConfigurationList","text":"Represents a list of component configurations. Properties:
array
The component configurationsobject
{\n \"configs\": [\n {\n \"definition\": {\n \"ad\": [\n {\n \"defaultValue\": \"true\",\n \"description\": \"Whether or not to enable the ClockService\",\n \"id\": \"enabled\",\n \"isRequired\": true,\n \"name\": \"enabled\",\n \"type\": \"BOOLEAN\"\n },\n {\n \"defaultValue\": \"true\",\n \"description\": \"Whether or not to sync the system hardware clock after the system time gets set\",\n \"id\": \"clock.set.hwclock\",\n \"isRequired\": true,\n \"name\": \"clock.set.hwclock\",\n \"type\": \"BOOLEAN\"\n },\n {\n \"defaultValue\": \"java-ntp\",\n \"description\": \"Source for setting the system clock. Verify the availabiliy of the selected provider before activate it.\",\n \"id\": \"clock.provider\",\n \"isRequired\": true,\n \"name\": \"clock.provider\",\n \"option\": [\n {\n \"label\": \"java-ntp\",\n \"value\": \"java-ntp\"\n },\n {\n \"label\": \"ntpd\",\n \"value\": \"ntpd\"\n },\n {\n \"label\": \"chrony-advanced\",\n \"value\": \"chrony-advanced\"\n }\n ],\n \"type\": \"STRING\"\n },\n {\n \"defaultValue\": \"0.pool.ntp.org\",\n \"description\": \"The hostname that provides the system time via NTP\",\n \"id\": \"clock.ntp.host\",\n \"isRequired\": true,\n \"name\": \"clock.ntp.host\",\n \"type\": \"STRING\"\n },\n {\n \"defaultValue\": \"123\",\n \"description\": \"The port number that provides the system time via NTP\",\n \"id\": \"clock.ntp.port\",\n \"isRequired\": true,\n \"max\": \"65535\",\n \"min\": \"1\",\n \"name\": \"clock.ntp.port\",\n \"type\": \"INTEGER\"\n },\n {\n \"defaultValue\": \"10000\",\n \"description\": \"The NTP timeout in milliseconds\",\n \"id\": \"clock.ntp.timeout\",\n \"isRequired\": true,\n \"min\": \"1000\",\n \"name\": \"clock.ntp.timeout\",\n \"type\": \"INTEGER\"\n },\n {\n \"defaultValue\": \"0\",\n \"description\": \"The maximum number of retries for the initial synchronization (with interval clock.ntp.retry.interval). If set to 0 the service will retry forever.\",\n \"id\": \"clock.ntp.max-retry\",\n \"isRequired\": true,\n \"min\": \"0\",\n \"name\": \"clock.ntp.max-retry\",\n \"type\": \"INTEGER\"\n },\n {\n \"defaultValue\": \"5\",\n \"description\": \"When sync fails, interval in seconds between each retry.\",\n \"id\": \"clock.ntp.retry.interval\",\n \"isRequired\": true,\n \"min\": \"1\",\n \"name\": \"clock.ntp.retry.interval\",\n \"type\": \"INTEGER\"\n },\n {\n \"defaultValue\": \"3600\",\n \"description\": \"Whether or not to sync the clock and if so, the frequency in seconds. If less than zero - no update, if equal to zero - sync once at startup, if greater than zero - the frequency in seconds to perform a new clock sync\",\n \"id\": \"clock.ntp.refresh-interval\",\n \"isRequired\": true,\n \"name\": \"clock.ntp.refresh-interval\",\n \"type\": \"INTEGER\"\n },\n {\n \"defaultValue\": \"/dev/rtc0\",\n \"description\": \"The RTC File Name. It defaults to /dev/rtc0. This option is not used if chrony-advanced option is selected in clock.provider.\",\n \"id\": \"rtc.filename\",\n \"isRequired\": true,\n \"name\": \"RTC File Name\",\n \"type\": \"STRING\"\n },\n {\n \"description\": \"Chrony configuration file.|TextArea\",\n \"id\": \"chrony.advanced.config\",\n \"isRequired\": false,\n \"name\": \"Chrony Configuration\",\n \"type\": \"STRING\"\n }\n ],\n \"description\": \"ClockService Configuration\",\n \"icon\": [\n {\n \"resource\": \"ClockService\",\n \"size\": 32\n }\n ],\n \"id\": \"org.eclipse.kura.clock.ClockService\",\n \"name\": \"ClockService\"\n },\n \"pid\": \"org.eclipse.kura.clock.ClockService\",\n \"properties\": {\n \"clock.ntp.host\": {\n \"type\": \"STRING\",\n \"value\": \"0.pool.ntp.org\"\n },\n \"clock.ntp.max-retry\": {\n \"type\": \"INTEGER\",\n \"value\": 0\n },\n \"clock.ntp.port\": {\n \"type\": \"INTEGER\",\n \"value\": 123\n },\n \"clock.ntp.refresh-interval\": {\n \"type\": \"INTEGER\",\n \"value\": 3600\n },\n \"clock.ntp.retry.interval\": {\n \"type\": \"INTEGER\",\n \"value\": 5\n },\n \"clock.ntp.timeout\": {\n \"type\": \"INTEGER\",\n \"value\": 10000\n },\n \"clock.provider\": {\n \"type\": \"STRING\",\n \"value\": \"java-ntp\"\n },\n \"clock.set.hwclock\": {\n \"type\": \"BOOLEAN\",\n \"value\": true\n },\n \"enabled\": {\n \"type\": \"BOOLEAN\",\n \"value\": true\n },\n \"kura.service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.clock.ClockService\"\n },\n \"rtc.filename\": {\n \"type\": \"STRING\",\n \"value\": \"/dev/rtc0\"\n },\n \"service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.clock.ClockService\"\n }\n }\n },\n {\n \"definition\": {\n \"ad\": [\n {\n \"defaultValue\": \"(kura.service.pid=org.eclipse.kura.ssl.SslManagerService)\",\n \"description\": \"Specifies, as an OSGi target filter, the pid of the SslManagerService used to create SSL connections for downloading packages.\",\n \"id\": \"SslManagerService.target\",\n \"isRequired\": true,\n \"name\": \"SslManagerService Target Filter\",\n \"type\": \"STRING\"\n }\n ],\n \"description\": \"This service is responsible of managing the deployment packages installed on the system.\",\n \"id\": \"org.eclipse.kura.deployment.agent\",\n \"name\": \"DeploymentAgent\"\n },\n \"pid\": \"org.eclipse.kura.deployment.agent\",\n \"properties\": {\n \"SslManagerService.target\": {\n \"type\": \"STRING\",\n \"value\": \"(kura.service.pid=org.eclipse.kura.ssl.SslManagerService)\"\n },\n \"kura.service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.deployment.agent\"\n },\n \"service.pid\": {\n \"type\": \"STRING\",\n \"value\": \"org.eclipse.kura.deployment.agent\"\n }\n }\n }\n ]\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#createfactorycomponentconfigurationsrequest","title":"CreateFactoryComponentConfigurationsRequest","text":"An object describing a factory component instance creation request. Properties:
configs: array
The set of configurations to be created
array elements: object
An object describing a factory component confguration. Properties:
pid: string
The component pid.
string
The component factory pidobject
bool
true
value will be used as default if not explicitly specified Defines whether a new snapshot should be created after that the factory component configuration instances have been created.{\n \"configs\": [\n {\n \"factoryPid\": \"org.eclipse.kura.core.db.H2DbServer\",\n \"pid\": \"testComponent\",\n \"properties\": {\n \"db.server.type\": {\n \"type\": \"STRING\",\n \"value\": \"WEB\"\n }\n }\n },\n {\n \"factoryPid\": \"org.eclipse.kura.core.db.H2DbServer\",\n \"pid\": \"thirdComponent\"\n }\n ],\n \"takeSnapshot\": true\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#updatecomponentconfigurationrequest","title":"UpdateComponentConfigurationRequest","text":"An object that describes a set of configurations that need to be updated. Properties:
array
The configurations to be updated. The ocd
field can be omitted, it will be ignored if specified.object
bool
true
value will be used as default if not explicitly specified Defines whether a new snapshot should be created after that the component configurations have been applied.{\n \"configs\": [\n {\n \"pid\": \"org.eclipse.kura.cloud.app.command.CommandCloudApp\",\n \"properties\": {\n \"command.enable\": {\n \"type\": \"BOOLEAN\",\n \"value\": true\n },\n \"command.timeout\": {\n \"type\": \"INTEGER\",\n \"value\": 60\n }\n }\n },\n {\n \"pid\": \"org.eclipse.kura.position.PositionService\",\n \"properties\": {\n \"parity\": {\n \"type\": \"STRING\",\n \"value\": 0\n }\n }\n }\n ],\n \"takeSnapshot\": true\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#deletefactorycomponentconfigurationsrequest","title":"DeleteFactoryComponentConfigurationsRequest","text":"An object describing a factory component instance delete request. Properties:
array
The list of the pids of the factory component instances to be deleted.string
The component pid.bool
true
value will be used as default if not explicitly specified Defines whether a new snapshot should be created after that the factory component configuration instances have been deleted.{\n \"pids\": [\n \"testComponent\",\n \"otherComponent\"\n ],\n \"takeSnapshot\": true\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#pidset","title":"PidSet","text":"Represents a set of pids or factory pids. Properties:
array
The set of pidsstring
The pid{\n \"pids\": [\n \"org.eclipse.kura.deployment.agent\",\n \"org.eclipse.kura.clock.ClockService\"\n ]\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#snaphsotid","title":"SnaphsotId","text":"An object describing the identifier of a configuration snapshot. Properties:
number
The snapshot id{\n \"id\": 163655959932\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#genericfailurereport","title":"GenericFailureReport","text":"An object reporting a failure message. Properties:
string
A message describing the failure.{\n \"message\": \"An unexpected error occurred.\"\n}\n
"},{"location":"references/rest-apis/rest-configuration-service-v2/#batchfailurereport","title":"BatchFailureReport","text":"An object that is returned by requests that involve multiple operations, when at least one operation failed. This object report an error message for each of the operations that failed. The operations are identified by an id, see request documentation for more details. If an operation is not listed by this object, then the operation succeeded. Properties:
failures: array
The list of operations that failed.
array elements: object
An object reporting details about an operation failure. Properties:
id: string
An identifier of the failed operation.
string
A message describing the failure.{\n \"failures\": [\n {\n \"id\": \"create:testComponent\",\n \"message\": \"Invalid parameter. pid testComponent already exists\"\n },\n {\n \"id\": \"create:otherComponent\",\n \"message\": \"Invalid parameter. pid otherComponent already exists\"\n }\n ]\n}\n
"},{"location":"references/rest-apis/rest-deploy-api/","title":"Rest Deploy v2 API","text":"The DeploymentRestService
APIs provides methods to manage the installed deployment packages. Identities with rest.deploy
permissions can access these APIs.
/deploy/v2/
[{ \"name\": \"packageName\", \"version\": \"packageVersion\"}]\n
"},{"location":"references/rest-apis/rest-deploy-api/#install-package-from-url","title":"Install package from URL","text":"/deploy/v2/_install
{\n \"url\": \"deploymentPackageUrl\"\n}\n
Example:
{\n \"url\": \"http://download.eclipse.org/kura/releases/4.1.0/org.eclipse.kura.demo.heater_1.0.500.dp\"\n}\n
Please note that the url can refer to a .dp
already in the device filesystem.
\"REQUEST_RECEIVED\"\n
"},{"location":"references/rest-apis/rest-deploy-api/#install-package-from-upload","title":"Install package from upload","text":"/deploy/v2/_upload
The POST request body should be encoded in the multipart/form-data
enctype
, thus allowing for the upload of the Deployment Package file. The uploaded file is expected to be added in the file
field of the form.
Content-Type
: multipart/form-data
file
Example using curl
:
curl -X POST -k -u $USERNAME:$PASSWORD \\\n --header 'Content-Type: multipart/form-data' \\\n --form 'file=@\"/path/to/your/file.dp\"' \\\n https://$ADDRESS/services/deploy/v2/_upload\n
"},{"location":"references/rest-apis/rest-deploy-api/#responses_2","title":"Responses","text":"\"REQUEST_RECEIVED\"\n
"},{"location":"references/rest-apis/rest-deploy-api/#uninstall-a-package","title":"Uninstall a package","text":"/deploy/v2/{name}
\"REQUEST_RECEIVED\"\n
"},{"location":"references/rest-apis/rest-deploy-api/#get-eclipse-marketplace-package-descriptor","title":"Get Eclipse Marketplace Package Descriptor","text":"/deploy/v2/_packageDescriptor
{\n \"url\": \"deploymentPackageUrl\"\n}\n
Example:
{\n \"url\": \"http://marketplace.eclipse.org/marketplace-client-intro?mpc_install=5514714\"\n}\n
"},{"location":"references/rest-apis/rest-deploy-api/#responses_4","title":"Responses","text":"{\n \"nodeId\":\"5514714\",\n \"url\":\"https://marketplace.eclipse.org/content/ai-wire-component-eclipse-kura-5\",\n \"dpUrl\":\"https://download.eclipse.org/kura/releases/5.3.0/org.eclipse.kura.wire.ai.component.provider-1.2.0.dp\",\n \"minKuraVersion\":\"5.1.0\",\n \"maxKuraVersion\":\"\",\n \"currentKuraVersion\":\"5.4.0\",\n \"isCompatible\":true\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v1/","title":"Rest Identity V1 API","text":"Warning
This API id deprecated and superseded by the Identity V2 REST APIs.
Note
This API can also be accessed via the RequestHandler with app-id: IDN-V1
.
The IdentityRestService
APIs provides methods to manage the system identities. Unless otherwise specified, identities with rest.identity
permissions can access these APIs.
services/identity/v1/identities
{\n \"userName\": \"username\",\n \"password\": \"password\",\n \"passwordChangeNeeded\": false,\n \"passwordAuthEnabled\": true,\n \"permissions\": [\n \"rest.identity\"\n ]\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v1/#responses","title":"Responses","text":"services/identity/v1/identities/byName
{\n \"userName\": \"username\"\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v1/#responses_1","title":"Responses","text":"{\n \"userName\": \"kura.user.username\",\n \"passwordAuthEnabled\": false,\n \"passwordChangeNeeded\": false,\n \"permissions\": []\n}\n
userName
does not existservices/identity/v1/definedPermissions
No specific permission is required to access this resource.
"},{"location":"references/rest-apis/rest-identity-api-v1/#responses_2","title":"Responses","text":"{\n \"permissions\": [\n \"rest.command\",\n \"rest.inventory\",\n \"rest.configuration\",\n \"rest.tamper.detection\",\n \"rest.security\",\n \"kura.cloud.connection.admin\",\n \"rest.position\",\n \"kura.packages.admin\",\n \"kura.device\",\n \"rest.wires.admin\",\n \"kura.admin\",\n \"rest.keystores\",\n \"rest.assets\",\n \"rest.system\",\n \"kura.maintenance\",\n \"kura.wires.admin\",\n \"rest.identity\"\n ]\n}\n
services/identity/v1/identities
{\n \"userConfig\": [\n {\n \"userName\": \"admin\",\n \"passwordAuthEnabled\": true,\n \"passwordChangeNeeded\": false,\n \"permissions\": [\n \"kura.admin\"\n ]\n },\n {\n \"userName\": \"appadmin\",\n \"passwordAuthEnabled\": true,\n \"passwordChangeNeeded\": true,\n \"permissions\": [\n \"kura.cloud.connection.admin\",\n \"kura.packages.admin\",\n \"kura.wires.admin\"\n ]\n }\n ]\n}\n
services/identity/v1/passwordRequirements
No specific permission is required to access this resource.
"},{"location":"references/rest-apis/rest-identity-api-v1/#responses_4","title":"Responses","text":"{\n \"passwordMinimumLength\": 8,\n \"passwordRequireDigits\": false,\n \"passwordRequireSpecialChars\": false,\n \"passwordRequireBothCases\": false\n}\n
services/identity/v1/identities
{\n \"userName\": \"username\",\n \"password\": \"password\",\n \"passwordChangeNeeded\": false,\n \"passwordAuthEnabled\": true,\n \"permissions\": [\n \"rest.identity\"\n ]\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v1/#responses_5","title":"Responses","text":"services/identity/v1/identities
{\n \"userName\": \"username\"\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v1/#responses_6","title":"Responses","text":"userName
does not existNote
This API can also be accessed via the RequestHandler with app-id: IDN-V2
.
The IdentityRestService
APIs provides methods to manage the system identities. Unless otherwise specified, identities with rest.identity
permissions can access these APIs.
services/identity/v2/identities
{\n \"name\": \"username\"\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#responses","title":"Responses","text":"name
(eg: nme
)identity
field is used to get only the name of specific identity. It is also possible to retrieve information about the specific user's component configuration, specifying the type of interest.services/identity/v2/identities/byName
{\n \"identity\": {\n \"name\": \"test\"\n }\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#response","title":"Response","text":"{\n \"identity\": {\n \"name\": \"username\"\n }\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#request_2","title":"Request","text":"{\n \"identity\": {\n \"name\": \"username\"\n }, \n \"configurationComponents\": [\"AdditionalConfigurations\", \"AssignedPermissions\", \"PasswordConfiguration\"]\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#response_1","title":"Response","text":"{\n \"identity\": {\n \"name\": \"username\"\n },\n \"permissionConfiguration\": {\n \"permissions\": [\n {\n \"name\": \"rest.identity\"\n }\n ]\n },\n \"passwordConfiguration\": {\n \"passwordChangeNeeded\": false,\n \"passwordAuthEnabled\": true\n },\n \"additionalConfigurations\": {\n \"configurations\": []\n }\n}\n
name
(eg: nme
)identity
field is used to get only the name of specific identity. It is also possible to retrieve information about the specific user's component default configuration, specifying the type of interest. This method accepts also non-existing user's name as input: in this way it's possible to retrieve which is the default configuration applied when a user is created with the name
field only.services/identity/v2/identities/default/byName
{\n\"identity\": {\n \"name\": \"username\"\n }\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#response_2","title":"Response","text":"{\n \"identity\": {\n \"name\": \"username\"\n }\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#request_4","title":"Request","text":"{\n \"identity\": {\n \"name\": \"username\"\n }, \n \"configurationComponents\": [\"AdditionalConfigurations\", \"AssignedPermissions\", \"PasswordConfiguration\"]\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#response_3","title":"Response","text":"{\n \"identity\": {\n \"name\": \"username\"\n },\n \"permissionConfiguration\": {\n \"permissions\": []\n },\n \"passwordConfiguration\": {\n \"passwordChangeNeeded\": false,\n \"passwordAuthEnabled\": false\n },\n \"additionalConfigurations\": {\n \"configurations\": []\n }\n}\n
name
(eg: nme
)services/identity/v2/permissions
{\n \"name\": \"permission\"\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#responses_1","title":"Responses","text":"identity
body field, or also the configurationComponents
one.services/identity/v2/identities/validate
{\n \"identity\": {\n \"name\": \"username\"\n }, \n \"configurationComponents\": [\"AdditionalConfigurations\", \"AssignedPermissions\", \"PasswordConfiguration\"]\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#responses_2","title":"Responses","text":"name
(eg: nme
)services/identity/v2/definedPermissions
No specific permission is required to access this resource.
"},{"location":"references/rest-apis/rest-identity-api-v2/#responses_3","title":"Responses","text":"[\n {\n \"name\": \"rest.identity\"\n },\n {\n \"name\": \"rest.wires.admin\"\n },\n {\n \"name\": \"kura.wires.admin\"\n },\n {\n \"name\": \"kura.network.admin\"\n },\n {\n \"name\": \"rest.network.status\"\n },\n {\n \"name\": \"test-permission\"\n },\n {\n \"name\": \"rest.keystores\"\n },\n {\n \"name\": \"rest.assets\"\n },\n {\n \"name\": \"rest.network.configuration\"\n },\n {\n \"name\": \"kura.admin\"\n },\n {\n \"name\": \"rest.cloudconnection\"\n },\n {\n \"name\": \"kura.device\"\n },\n {\n \"name\": \"rest.system\"\n },\n {\n \"name\": \"kura.maintenance\"\n },\n {\n \"name\": \"kura.packages.admin\"\n },\n {\n \"name\": \"rest.tamper.detection\"\n },\n {\n \"name\": \"rest.deploy\"\n },\n {\n \"name\": \"rest.configuration\"\n },\n {\n \"name\": \"kura.cloud.connection.admin\"\n },\n {\n \"name\": \"rest.command\"\n },\n {\n \"name\": \"rest.inventory\"\n },\n {\n \"name\": \"rest.position\"\n },\n {\n \"name\": \"rest.security\"\n }\n]\n
services/identity/v2/identities
[\n {\n \"identity\": {\n \"name\": \"admin\"\n },\n \"permissionConfiguration\": {\n \"permissions\": [\n {\n \"name\": \"kura.admin\"\n }\n ]\n },\n \"passwordConfiguration\": {\n \"passwordChangeNeeded\": false,\n \"passwordAuthEnabled\": true\n },\n \"additionalConfigurations\": {\n \"configurations\": []\n }\n },\n {\n \"identity\": {\n \"name\": \"appadmin\"\n },\n \"permissionConfiguration\": {\n \"permissions\": [\n {\n \"name\": \"kura.packages.admin\"\n },\n {\n \"name\": \"kura.cloud.connection.admin\"\n },\n {\n \"name\": \"kura.wires.admin\"\n }\n ]\n },\n \"passwordConfiguration\": {\n \"passwordChangeNeeded\": true,\n \"passwordAuthEnabled\": true\n },\n \"additionalConfigurations\": {\n \"configurations\": []\n }\n },\n {\n \"identity\": {\n \"name\": \"netadmin\"\n },\n \"permissionConfiguration\": {\n \"permissions\": [\n {\n \"name\": \"kura.device\"\n },\n {\n \"name\": \"kura.network.admin\"\n },\n {\n \"name\": \"kura.cloud.connection.admin\"\n }\n ]\n },\n \"passwordConfiguration\": {\n \"passwordChangeNeeded\": true,\n \"passwordAuthEnabled\": true\n },\n \"additionalConfigurations\": {\n \"configurations\": []\n }\n }\n]\n
services/identity/v2/passwordStrenghtRequirements
No specific permission is required to access this resource.
"},{"location":"references/rest-apis/rest-identity-api-v2/#responses_5","title":"Responses","text":"{\n \"passwordMinimumLength\": 8,\n \"digitsRequired\": false,\n \"specialCharactersRequired\": false,\n \"bothCasesRequired\": false\n}\n
services/identity/v2/identities
{\n \"identity\": {\n \"name\": \"username\"\n },\n \"permissionConfiguration\": {\n \"permissions\": [\n {\n \"name\": \"rest.identity\"\n }\n ]\n },\n \"passwordConfiguration\": {\n \"passwordChangeNeeded\": false,\n \"passwordAuthEnabled\": true,\n \"password\": \"password123\"\n }\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#responses_6","title":"Responses","text":"name
(eg: nme
)name
.services/identity/v2/identities
{\n \"name\": \"username\"\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#responses_7","title":"Responses","text":"username
does not existname
(eg: nme
)name
.services/identity/v2/permissions
{\n \"name\": \"permission\"\n}\n
"},{"location":"references/rest-apis/rest-identity-api-v2/#responses_8","title":"Responses","text":"permission
does not existname
(eg: nme
)/services/inventory/v1/inventory
{\n \"inventory\":[\n {\n \"name\":\"adduser\",\n \"version\":\"3.118\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"com.eclipsesource.jaxrs.provider.gson\",\n \"version\":\"2.3.0.201602281253\",\n \"type\":\"BUNDLE\"\n },\n {\n \"name\":\"org.eclipse.kura.example.beacon\",\n \"version\":\"1.0.500\",\n \"type\":\"DP\"\n }\n ]\n}\n
/services/inventory/v1/bundles
{\n \"bundles\":[\n {\n \"name\":\"org.eclipse.osgi\",\n \"version\":\"3.16.0.v20200828-0759\",\n \"id\":0,\n \"state\":\"ACTIVE\",\n \"signed\":true\n },\n {\n \"name\":\"org.eclipse.equinox.cm\",\n \"version\":\"1.4.400.v20200422-1833\",\n \"id\":1,\n \"state\":\"ACTIVE\",\n \"signed\":false\n }\n ]\n}\n
/services/inventory/v1/bundles/_start
{ \n\"name\":\"org.eclipse.osgi\",\n}\n
"},{"location":"references/rest-apis/rest-inventory-api/#responses","title":"Responses","text":"/services/inventory/v1/bundles/_stop
{ \n\"name\":\"org.eclipse.osgi\",\n}\n
"},{"location":"references/rest-apis/rest-inventory-api/#responses_1","title":"Responses","text":"/services/inventory/v1/deploymentPackages
{\n \"deploymentPackages\":[\n {\n \"name\":\"org.eclipse.kura.example.beacon\",\n \"version\":\"1.0.500\",\n \"signed\":false,\n \"bundles\":[\n {\n \"name\":\"org.eclipse.kura.example.beacon\",\n \"version\":\"1.0.500\",\n \"id\": 171,\n \"state\": \"ACTIVE\",\n \"signed\": false\n }\n ]\n }\n ]\n}\n
/services/inventory/v1/systemPackages
{\n \"systemPackages\":[\n {\n \"name\":\"adduser\",\n \"version\":\"3.118\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"alsa-utils\",\n \"version\":\"1.1.8-2\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"ansible\",\n \"version\":\"2.7.7+dfsg-1\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"apparmor\",\n \"version\":\"2.13.2-10\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"apt\",\n \"version\":\"1.8.2.1\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"apt-listchanges\",\n \"version\":\"3.19\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"apt-transport-https\",\n \"version\":\"1.8.2.2\",\n \"type\":\"DEB\"\n },\n {\n \"name\":\"apt-utils\",\n \"version\":\"1.8.2.1\",\n \"type\":\"DEB\"\n }\n ]\n}\n
/services/inventory/v1/containers
{\n \"containers\":\n [\n {\n \"name\":\"container_1\",\n \"version\":\"nginx:latest\",\n \"type\":\"DOCKER\",\n \"state\":\"active\"\n }\n ]\n}\n
/services/inventory/v1/containers/_start
{\n \"name\":\"container_1\",\n \"version\": \"nginx:latest\",\n}\n
"},{"location":"references/rest-apis/rest-inventory-api/#responses_2","title":"Responses","text":"/services/inventory/v1/containers/_stop
{\n \"name\":\"container_1\",\n \"version\": \"nginx:latest\",\n}\n
"},{"location":"references/rest-apis/rest-inventory-api/#responses_3","title":"Responses","text":"/services/inventory/v1/images
{\n \"containers\":\n [\n {\n \"name\":\"nginx\",\n \"version\":\"latest\",\n \"type\":\"ContainerImage\",\n }\n ]\n}\n
/services/inventory/v1/images/_delete
{\n \"name\":\"nginx\",\n \"version\":\"latest\",\n}\n
"},{"location":"references/rest-apis/rest-inventory-api/#responses_4","title":"Responses","text":"- `ACTIVE`: Container is running\n- `INSTALLED`: Container is starting\n- `UNINSTALLED`: Container has failed, or is stopped\n- `UNKNOWN`: Container state can not be determined\n
"},{"location":"references/rest-apis/rest-inventory-api/#container-states","title":"Container States","text":"- `active`: Container is running\n- `installed`: Container is starting\n- `uninstalled`: Container has failed, or is stopped\n- `unknown`: Container state can not be determined\n
"},{"location":"references/rest-apis/rest-network-configuration-api/","title":"Network Configuration V1 REST APIs","text":"This section describes the networkConfiguration/v1
REST APIs, that allow to retrieve information about the network configuration of the running system. The services pid
for which it's possible to obtain and update the configurations are:
org.eclipse.kura.net.admin.NetworkConfigurationService
: which manages the network configuration of the system, so the network interfaces along with their network configuration (Ip4/Ip6 settings, DHCP, Nat, and so on)org.eclipse.kura.net.admin.FirewallConfigurationService
: which manages the Ip4 firewall configurations (open ports, port forwarding and masquerading for IPv4 protocol)org.eclipse.kura.net.admin.ipv6.FirewallConfigurationServiceIPv6
: which manages the Ip6 firewall configurations (open ports, port forwarding and masquerading for IPv6 protocol)To access these REST APIs, an identity with rest.network.configuration
permission assigned is required.
/services/networkConfiguration/v1/configurableComponents
/services/networkConfiguration/v1/configurableComponents/configurations
pid
, ocd
and properties
./services/networkConfiguration/v1/configurableComponents/configurations/byPid
pid
, ocd
and properties
./services/networkConfiguration/v1/configurableComponents/configurations/byPid/_default
pid
, ocd
and properties
./services/networkConfiguration/v1/configurableComponents/configurations/_update
update:$pid
for component update operations, where $pid
is the pid of the instance, and snapshot
, for the snapshot creation operation. In case of an unexpected failure, a generic error response will be returned.Warning
factoryComponents
endopoints are available in the current version of Kura for future compatibility. Currently, as of Kura 5.4.0, there are no network related components that are factory components.
The endopoints that should return a list of pids will always return an empty array, while those that should create, delete or update a component will always return a 500 error.
"},{"location":"references/rest-apis/rest-network-configuration-api/#getfactorycomponents","title":"GET/factoryComponents","text":"/services/networkConfiguration/v1/factoryComponents
/services/networkConfiguration/v1/factoryComponents
500
description : In case of processing errors, the device will attempt to return a detailed error response containing a message describing the failure reason for each operation. The operation ids are the following: create:$pid
for component creation operations, where $pid
is the pid of the instance, and snapshot
, for the snapshot creation operation. In case of an unexpected failure, a generic error response will be returned.
response body :
/services/networkConfiguration/v1/factoryComponents/byPid
delete:$pid
for component delete operations, where $pid
is the pid of the instance, and snapshot
, for the snapshot creation operation. In case of an unexpected failure, a generic error response will be returned./services/networkConfiguration/v1/factoryComponents/ocd
pid
property of the received configurations will report the factory pid, the ocd
field will contain the definition, the properties
field will not be present./services/networkConfiguration/v1/factoryComponents/ocd/byFactoryPid
pid
property of the received configurations will report the factory pid, the ocd
field will contain the definition, the properties
field will not be present. If the OCD for a given factory pid cannot be found, it will not be included in the result.An object that is returned by requests that involve multiple operations, when at least one operation failed. This object report an error message for each of the operations that failed. The operations are identified by an id, see request documentation for more details. If an operation is not listed by this object, then the operation succeeded. Properties:
failures: array
The list of operations that failed.
array elements: object
An object reporting details about an operation failure. Properties:
id: string
An identifier of the failed operation.
string
A message describing the failure.{\n \"failures\": [\n {\n \"id\": \"create:testComponent\",\n \"message\": \"Invalid parameter. pid testComponent already exists\"\n },\n {\n \"id\": \"create:otherComponent\",\n \"message\": \"Invalid parameter. pid otherComponent already exists\"\n }\n ]\n}\n
"},{"location":"references/rest-apis/rest-network-configuration-api/#componentconfigurationlist","title":"ComponentConfigurationList","text":"Represents a list of component configurations. Properties:
array
The component configurationsobject
{\n \"configs\": [\n {\n \"pid\": \"org.eclipse.kura.net.admin.FirewallConfigurationService\",\n \"definition\": {\n \"ad\": [\n {\n \"name\": \"firewall.open.ports\",\n \"description\": \"The list of firewall opened ports.\",\n \"id\": \"firewall.open.ports\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"\",\n \"isRequired\": true\n },\n {\n \"name\": \"firewall.port.forwarding\",\n \"description\": \"The list of firewall port forwarding rules.\",\n \"id\": \"firewall.port.forwarding\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"\",\n \"isRequired\": true\n },\n {\n \"name\": \"firewall.nat\",\n \"description\": \"The list of firewall NAT rules.\",\n \"id\": \"firewall.nat\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"\",\n \"isRequired\": true\n }\n ],\n \"name\": \"FirewallConfigurationService\",\n \"description\": \"Firewall Configuration Service\",\n \"id\": \"org.eclipse.kura.net.admin.FirewallConfigurationService\"\n },\n \"properties\": {\n \"firewall.open.ports\": {\n \"value\": \"22,tcp,0.0.0.0/0,eth0,,,,#;22,tcp,0.0.0.0/0,wlan0,,,,#;443,tcp,0.0.0.0/0,eth0,,,,#;443,tcp,0.0.0.0/0,wlan0,,,,#;4443,tcp,0.0.0.0/0,eth0,,,,#;4443,tcp,0.0.0.0/0,wlan0,,,,#;1450,tcp,0.0.0.0/0,eth0,,,,#;1450,tcp,0.0.0.0/0,wlan0,,,,#;5002,tcp,127.0.0.1/32,,,,,#;53,udp,0.0.0.0/0,eth0,,,,#;53,udp,0.0.0.0/0,wlan0,,,,#;67,udp,0.0.0.0/0,eth0,,,,#;67,udp,0.0.0.0/0,wlan0,,,,#;8000,tcp,0.0.0.0/0,eth0,,,,#;8000,tcp,0.0.0.0/0,wlan0,,,,#\",\n \"type\": \"STRING\"\n },\n \"firewall.port.forwarding\": {\n \"value\": \"\",\n \"type\": \"STRING\"\n },\n \"firewall.nat\": {\n \"value\": \"\",\n \"type\": \"STRING\"\n },\n \"kura.service.pid\": {\n \"value\": \"org.eclipse.kura.net.admin.FirewallConfigurationService\",\n \"type\": \"STRING\"\n },\n \"service.pid\": {\n \"value\": \"org.eclipse.kura.net.admin.FirewallConfigurationService\",\n \"type\": \"STRING\"\n }\n }\n },\n {\n \"pid\": \"org.eclipse.kura.net.admin.ipv6.FirewallConfigurationServiceIPv6\",\n \"definition\": {\n \"ad\": [\n {\n \"name\": \"firewall.ipv6.open.ports\",\n \"description\": \"The list of firewall opened ports.\",\n \"id\": \"firewall.ipv6.open.ports\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"\",\n \"isRequired\": true\n },\n {\n \"name\": \"firewall.ipv6.port.forwarding\",\n \"description\": \"The list of firewall port forwarding rules.\",\n \"id\": \"firewall.ipv6.port.forwarding\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"\",\n \"isRequired\": true\n },\n {\n \"name\": \"firewall.ipv6.nat\",\n \"description\": \"The list of firewall NAT rules.\",\n \"id\": \"firewall.ipv6.nat\",\n \"type\": \"STRING\",\n \"cardinality\": 0,\n \"defaultValue\": \"\",\n \"isRequired\": true\n }\n ],\n \"name\": \"FirewallConfigurationServiceIPv6\",\n \"description\": \"Firewall Configuration Service IPV6\",\n \"id\": \"org.eclipse.kura.net.admin.ipv6.FirewallConfigurationServiceIPv6\"\n },\n \"properties\": {\n \"firewall.ipv6.port.forwarding\": {\n \"value\": \"\",\n \"type\": \"STRING\"\n },\n \"firewall.ipv6.nat\": {\n \"value\": \"\",\n \"type\": \"STRING\"\n },\n \"firewall.ipv6.open.ports\": {\n \"value\": \"1234,tcp,0:0:0:0:0:0:0:0/0,,,,,#\",\n \"type\": \"STRING\"\n },\n \"kura.service.pid\": {\n \"value\": \"org.eclipse.kura.net.admin.ipv6.FirewallConfigurationServiceIPv6\",\n \"type\": \"STRING\"\n },\n \"service.pid\": {\n \"value\": \"org.eclipse.kura.net.admin.ipv6.FirewallConfigurationServiceIPv6\",\n \"type\": \"STRING\"\n }\n }\n }\n ]\n}\n
"},{"location":"references/rest-apis/rest-network-configuration-api/#genericfailurereport","title":"GenericFailureReport","text":"An object reporting a failure message. Properties:
string
A message describing the failure.{\n \"message\": \"An unexpected error occurred.\"\n}\n
"},{"location":"references/rest-apis/rest-network-configuration-api/#pidset","title":"PidSet","text":"Represents a set of pids or factory pids. Properties:
array
The set of pidsstring
The pid{\n \"pids\": [\n \"org.eclipse.kura.net.admin.ipv6.FirewallConfigurationServiceIPv6\",\n \"org.eclipse.kura.net.admin.NetworkConfigurationService\",\n \"org.eclipse.kura.net.admin.FirewallConfigurationService\"\n ]\n}\n
"},{"location":"references/rest-apis/rest-network-configuration-api/#updatecomponentconfigurationrequest","title":"UpdateComponentConfigurationRequest","text":"An object that describes a set of configurations that need to be updated. Properties:
array
The configurations to be updated. The ocd
field can be omitted, it will be ignored if specified.object
bool
true
value will be used as default if not explicitly specified Defines whether a new snapshot should be created after that the component configurations have been applied.{\n \"configs\": [\n {\n \"pid\": \"org.eclipse.kura.net.admin.ipv6.FirewallConfigurationServiceIPv6\",\n \"properties\": {\n \"firewall.ipv6.open.ports\": {\n \"value\": \"1234,tcp,0:0:0:0:0:0:0:0/0,,,,,#\",\n \"type\": \"STRING\"\n }\n }\n },\n {\n \"pid\": \"org.eclipse.kura.net.admin.NetworkConfigurationService\",\n \"properties\": {\n \"net.interface.eth0.config.ip6.status\": {\n \"value\": \"netIPv6StatusUnmanaged\",\n \"type\": \"STRING\"\n }\n }\n }\n ],\n \"takeSnapshot\": true\n}\n
"},{"location":"references/rest-apis/rest-position-api/","title":"Position","text":"Note
This API can also be accessed via the RequestHandler with app-id: POS-V1
.
/services/position/v1/position
{\n //longitude of this position in degrees.\n \"longitude\": 7.729571119959449,\n\n //latitude of this position in degrees.\n \"latitude\": 50.45345802194789,\n\n //altitude of this position in meters.\n \"altitude\": 1000.0,\n\n //the ground speed of this position in meters per second.\n \"speed\": 1000.0,\n\n //the track of this position in degrees as a compass heading.\n \"track\": 1000.0\n\n //the gnss system used to retrieve position information\n \"gnssType\": [\n \"Gps\"\n ]\n}\n
{\n \"message\": \"Service unavailable. Position is not locked.\"\n}\n
/services/position/v1/dateTime
{\n //The dateTime string is formatted according to the ISO 8601 standard, and will always be in the UTC timezone. \n \"dateTime\": \"2023-07-19T18:26:38Z\"\n}\n
{\n \"message\": \"Service unavailable. Position is not locked.\"\n}\n
/services/position/v1/isLocked
{\n \"islocked\": false\n}\n
- 500 Internal Server Error"},{"location":"references/rest-apis/rest-security-api-v1/","title":"Rest Security V1 API","text":"Warning
This API id deprecated and superseded by the Security V2 REST APIs.
Note
This API can also be accessed via the RequestHandler with app-id: SEC-V1
.
This REST API requires a SecurityService implementation to be registered on the framework, which is not provided by the standard Kura distribution.
The SecurityRestService
APIs provides methods to manage the system security. Identities with rest.security
permissions can access these APIs.
services/security/v1/security-policy-fingerprint/reload
SecurityService
implementation is available)services/security/v1/command-line-fingerprint/reload
SecurityService
implementation is available)Note
Access to this resource doesn't require the rest.security
permission.
services/security/v1/debug-enabled
{\n \"enabled\":true\n}\n
SecurityService
implementation is available)Note
This API can also be accessed via the RequestHandler with app-id: SEC-V2
.
This REST API requires a SecurityService implementation to be registered on the framework, which is not provided by the standard Kura distribution.
The SecurityRestService
APIs provides methods to manage the system security. Identities with rest.security
permissions can access these APIs.
services/security/v2/security-policy-fingerprint/reload
SecurityService
implementation is available)services/security/v2/command-line-fingerprint/reload
SecurityService
implementation is available)services/security/v2/security-policy/apply-default-production
SecurityService
implementation is available)services/security/v2/security-policy/apply
<plain text security policy>\n
"},{"location":"references/rest-apis/rest-security-api-v2/#responses_3","title":"Responses","text":"SecurityService
implementation is available)Note
Access to this resource doesn't require the rest.security
permission.
services/security/v2/debug-enabled
{\n \"enabled\":true\n}\n
SecurityService
implementation is available)Note
This API can also be accessed via the RequestHandler with app-id: SVCLIST-V1
.
The SVCLIST-V1 cloud request handler and the corresponding REST APIs allow to retrieve the identifiers (kura.service.pid) of the service running on the system that match user provided search criteria.
KeystoreService
and TruststoreKeystoreService
defined by the org.eclipse.kura.ssl.SslManagerService
component.A list of serviceinterface names.
Properties:
interfaceNames: array
The list of service interface names.
string
A service interface name.{\n \"interfaceNames\": [\n \"org.eclipse.kura.security.keystore.KeystoreService\",\n \"org.eclipse.kura.configuration.ConfigurableComponent\"\n ]\n}\n
"},{"location":"references/rest-apis/rest-service-listing-api/#reference","title":"Reference","text":"A object specifying a service pid and a reference name.
Properties:
pid: string
The pid of the service containing the reference
referenceName: string
The reference name
{\n \"pid\": \"org.eclipse.kura.ssl.SslManagerService\",\n \"referenceName\": \"KeystoreService\"\n}\n
"},{"location":"references/rest-apis/rest-service-listing-api/#propertyfilter","title":"PropertyFilter","text":"A filter matching property keys and values. If the value
property omitted, the filter will match if the property is set, regardless of the value. If the service property value is of array or list type, the filter will match if at least one of the elements match.
Properties:
name: string
The property name that should be matched, it must not contain spaces
value: string
(optional) The property value that should be matched.
{\n \"name\": \"foo\",\n \"value\": \"bar\"\n}\n
{\n \"name\": \"foo\"\n}\n
"},{"location":"references/rest-apis/rest-service-listing-api/#notfilter","title":"NotFilter","text":"A filter that negates the result returned by the filter specified as the \"not\" propertiy.
Properties:
object
{\n \"not\": {\n \"name\": \"foo\",\n \"value\": \"bar\"\n }\n}\n
"},{"location":"references/rest-apis/rest-service-listing-api/#andfilter","title":"AndFilter","text":"A filter that matches if all filters specified by the \"and\" propertiy match.
Properties:
and: array
A list of filters that should be combined with the and operator
object
{\n \"and\": [\n {\n \"name\": \"foo\",\n \"value\": \"bar\"\n },\n {\n \"name\": \"baz\"\n }\n ]\n}\n
"},{"location":"references/rest-apis/rest-service-listing-api/#orfilter","title":"OrFilter","text":"A filter that matches if any of the filters specified by the \"or\" propertiy match.
Properties:
or: array
A list of filters that should be combined with the or operator
object
{\n \"or\": [\n {\n \"name\": \"foo\",\n \"value\": \"bar\"\n },\n {\n \"name\": \"baz\"\n }\n ]\n}\n
"},{"location":"references/rest-apis/rest-service-listing-api/#filter","title":"Filter","text":"A filter that operates on service properties. This object allows to specify basic property key/value matchers and the and
or
and not
operators.
Represents a set of pids or factory pids.
Properties:
pids: array
The set of pids
string
The pid{\n \"pids\": [\n \"org.eclipse.kura.cloud.app.command.CommandCloudApp\",\n \"org.eclipse.kura.cloud.CloudService\",\n \"org.eclipse.kura.cloud.publisher.CloudNotificationPublisher\",\n \"org.eclipse.kura.container.orchestration.provider.ContainerOrchestrationService\",\n \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\",\n \"org.eclipse.kura.core.deployment.CloudDeploymentHandlerV2\",\n \"org.eclipse.kura.crypto.CryptoService\",\n \"org.eclipse.kura.data.DataService\",\n \"org.eclipse.kura.db.H2DbService\",\n \"org.eclipse.kura.deployment.agent\"\n ]\n}\n
"},{"location":"references/rest-apis/rest-service-listing-api/#genericfailurereport","title":"GenericFailureReport","text":"An object reporting a failure message.
Properties:
string
A message describing the failure.The session management REST APIs allow to authenticate and establish an HTTP session. Using this APIs and creating a session is the recommended way for interact with Kura rest APIs from a browser based application.
The supported workflows are the following:
"},{"location":"references/rest-apis/rest-session-api/#login-and-resource-access-workflow","title":"Login and resource access workflow","text":"Try calling the GET/xsrfToken to get an XSRF token, if the request succeeds a vaild session is already available, it is possible to proceed to step 4.
Call the POST/login/password or POST/login/certificate providing the credentials to create a new session.
This request will return a session cookie with the response. The session cookie name is currently JSESSIONID
. It is important to provide the received cookies in successive requests using the Cookie HTTP request header. If this is not done, requests will fail with 401 code. If the request is performed by a browser, cookie management should be performed automatically.
If password authentication has been used and the response object reports that a password change is needed, perform the Update password workflow
Repeat step 1. to get an XSRF token.
Access the desired resources, set the XSRF token previously obtained as the value of the X-XSRF-Token
HTTP header on each request. If a reuqest fails with error code 401, proceed to step 2.
curl
","text":""},{"location":"references/rest-apis/rest-session-api/#1-login-with-usernamepassword-and-collect-the-session-cookie","title":"1. Login with username/password and collect the session cookie","text":"curl -k -X POST \\\n -H 'Content-Type: application/json' \\\n https://$ADDRESS/services/session/v1/login/password \\\n -d '{\"password\": \"$KURA_PASS\", \"username\": \"$KURA_USER\"}' -v\n
where:
$ADDRESS
: is the address of the Kura instance$KURA_USER
: is the Kura username$KURA_PASS
: is the Kura passwordin the log you should find a JSESSIONID
you'll use in subsequent requests
...\n< HTTP/1.1 200 OK\n< Date: Tue, 14 Nov 2023 08:17:26 GMT\n< Set-Cookie: JSESSIONID=myawesomecookie; Path=/; Secure; HttpOnly\n< Expires: Thu, 01 Jan 1970 00:00:00 GMT\n< Content-Type: application/json\n< Content-Length: 30\n<\n* Connection #0 to host 192.168.1.111 left intact\n{\"passwordChangeNeeded\":false}%\n
"},{"location":"references/rest-apis/rest-session-api/#2-retrieve-the-xsrf-token","title":"2. Retrieve the XSRF token","text":"curl -k -X GET \\\n -b \"JSESSIONID=myawesomecookie\" \\\n https://$ADDRESS/services/session/v1/xsrfToken\n
in the response you'll find your XSRF token you'll need to use in subsequent requests
{\"xsrfToken\":\"myawesometoken\"}%\n
"},{"location":"references/rest-apis/rest-session-api/#3-access-the-resource","title":"3. Access the resource","text":"Using the Cookie and the XSRF token you just retrieved you can access your desired resource
curl -k -X GET \\\n -H 'X-XSRF-Token: myawesometoken' \\\n -b \"JSESSIONID=myawesomecookie\" \\\n https://$ADDRESS/services/deploy/v2/\n
"},{"location":"references/rest-apis/rest-session-api/#update-password-workflow","title":"Update password workflow","text":"Get an XSRF token using the GET/xsrfToken endpoint.
Call the POST/changePassword, providing both the new and old password, make sure to include the X-XSRF-Token
HTTP header.
Repeat the Authentication and resource access workflow, starting from step 1.
Sessions will expire after an inactivity interval that can be configured using the Session Inactivity Interval (Seconds) RestService configuration parameter. After session expiration, a new login will be necessary.
In order to add protection against XSRF attacks, it is necessary to provide an token using the X-XSRF-Token
HTTP header in all requests. The token can be obtained using the GET/xsrfToken endpoint after a successful login.
Session will be invalidated if the current identity credentials are changed, in this case a new login will be necessary.
If a password change is required for the current identity, it will be necessary to perform the Update password workflow before being able to access the other resources.
"},{"location":"references/rest-apis/rest-session-api/#reference","title":"Reference","text":"identity/v1/passwordRequirements
endpoint.Represents the response for a successful authentication request.
Properties:
bool
Determines whether a password change is required for the current identity.{\n \"passwordChangeNeeded\": true\n}\n
"},{"location":"references/rest-apis/rest-session-api/#usernamepassword","title":"UsernamePassword","text":"Contains an username and password.
Properties:
username: string
The user name.
password: string
The user password.
{\n \"password\": \"bar\",\n \"username\": \"foo\"\n}\n
"},{"location":"references/rest-apis/rest-session-api/#xsrftoken","title":"XSRFToken","text":"An object containing an XSRF token.
Properties:
string
The XSRF token.{\n \"xsrfToken\": \"d2b68613-152f-41d5-8b5b-a19448ed0e4e\"\n}\n
"},{"location":"references/rest-apis/rest-session-api/#passwordchangerequest","title":"PasswordChangeRequest","text":"An object containing the current password and a new password.
Properties:
currentPassword: string
The current password.
newPassword: string
The new password.
{\n \"currentPassword\": \"foo\",\n \"newPassword\": \"bar\"\n}\n
"},{"location":"references/rest-apis/rest-session-api/#identityinfo","title":"IdentityInfo","text":"An object containing information about the current identity
Properties:
name: string
The name of the current identity.
passwordChangeNeeded: bool
Determines whether a password change is required for the current identity.
permissions: array
The list of permissions assigned to the current identity.
string
The permission name.{\n \"name\": \"foo\",\n \"passwordChangeNeeded\": false,\n \"permissions\": [\n \"rest.bar\",\n \"rest.assets\",\n \"rest.foo\"\n ]\n}\n
"},{"location":"references/rest-apis/rest-session-api/#authenticationinfo","title":"AuthenticationInfo","text":"An object containing information about the enabled authentication methods.
Properties:
passwordAuthenticationEnabled: bool
Reports whether authentication using the login/password
endpoint is enabled.
certificateAuthenticationEnabled: bool
Reports whether authentication using the login/certificate
endpoint is enabled.
certificateAuthenticationPorts: array
(optional) The list of ports available for certificate based authentication. This property will be present only if certificateAuthenticationEnabled
is true
string
A port that can be used for certificate based authentication.message: string
(optional) Reports the content of the Login Banner, if configured on the device. A browser based application should display this message to the user before login if this property is set. This property will be missing if the login banner is not enabled.
{\n \"certificateAuthenticationEnabled\": false,\n \"passwordAuthenticationEnabled\": true\n}\n
{\n \"certificateAuthenticationEnabled\": true,\n \"certificateAuthenticationPorts\": [\n 4443,\n 4444\n ],\n \"passwordAuthenticationEnabled\": true\n}\n
{\n \"certificateAuthenticationEnabled\": false,\n \"message\": \"login banner content\",\n \"passwordAuthenticationEnabled\": true\n}\n
"},{"location":"references/rest-apis/rest-session-api/#genericfailurereport","title":"GenericFailureReport","text":"An object reporting a failure message.
Properties:
string
A message describing the failure.Note
This API can also be accessed via the RequestHandler with app-id: SYS-V1
.
The SystemService
APIs return properties that are divided into 3 categories:
Identities with rest.system
permissions can access these APIs.
Note
Some of the listed properties, depending on the device, might not be available.
"},{"location":"references/rest-apis/rest-system-api/#get-methods","title":"GET methods","text":""},{"location":"references/rest-apis/rest-system-api/#get-framework-properties","title":"Get framework properties","text":"/services/system/v1/properties/framework
{\n \"biosVersion\": \"N/A\",\n \"cpuVersion\": \"unknown\",\n \"deviceName\": \"raspberry\",\n \"modelId\": \"raspberry\",\n \"modelName\": \"raspberry\",\n \"partNumber\": \"raspberry\",\n \"platform\": \"aarch64\",\n \"numberOfProcessors\": 4,\n \"totalMemory\": 506816,\n \"freeMemory\": 380379,\n \"serialNumber\": \"10000000ba7c7bfd\",\n \"javaHome\": \"/usr/lib/jvm/java-8-openjdk-armhf/jre\",\n \"javaVendor\": \"OpenJDK Runtime Environment\",\n \"javaVersion\": \"1.8.0_312-8u312-b07-1+rpi1-b07\",\n \"javaVmInfo\": \"mixed mode\",\n \"javaVmName\": \"OpenJDK Client VM\",\n \"javaVmVersion\": \"25.312-b07\",\n \"javaVmVendor\": \"Temurin\",\n \"jdkVendorVersion\": \"Zulu 8.70.0.24-SA-linux64\",\n \"osArch\": \"arm\",\n \"osDistro\": \"Linux\",\n \"osDistroVersion\": \"N/A\",\n \"osName\": \"Linux\",\n \"osVersion\": \"6.1.21-v8+ #1642 SMP PREEMPT Mon Apr 3 17:24:16 BST 2023\",\n \"isLegacyBluetoothBeaconScan\": false,\n \"isLegacyPPPLoggingEnabled\": true,\n \"primaryMacAddress\": \"E4:5F:01:35:7F:F4\",\n \"primaryNetworkInterfaceName\": \"eth0\",\n \"fileSeparator\": \"/\",\n \"firmwareVersion\": \"N/A\",\n \"kuraDataDirectory\": \"/opt/eclipse/kura/data\",\n \"kuraFrameworkConfigDirectory\": \"/opt/eclipse/kura/framework\",\n \"kuraHomeDirectory\": \"/opt/eclipse/kura\",\n \"kuraMarketplaceCompatibilityVersion\": \"5.4.0.SNAPSHOT\",\n \"kuraSnapshotsCount\": 10,\n \"kuraSnapshotsDirectory\": \"/opt/eclipse/kura/user/snapshots\",\n \"kuraStyleDirectory\": \"/opt/eclipse/kura/console/skin\",\n \"kuraTemporaryConfigDirectory\": \"/tmp/.kura\",\n \"kuraUserConfigDirectory\": \"/opt/eclipse/kura/user\",\n \"kuraVersion\": \"KURA_5.4.0-SNAPSHOT\",\n \"kuraHaveWebInterface\": true,\n \"kuraHaveNetAdmin\": true,\n \"kuraWifiTopChannel\": 2147483647,\n \"kuraDefaultNetVirtualDevicesConfig\": \"netIPv4StatusUnmanaged\",\n \"osgiFirmwareName\": \"Eclipse\",\n \"osgiFirmwareVersion\": \"1.10.0\",\n \"commandUser\": \"kura\",\n \"commandZipMaxUploadNumber\": 1024,\n \"commandZipMaxUploadSize\": 100\n}\n
/services/system/v1/properties/extended
{\n \"version\": \"1.0\",\n \"extendedProperties\": {\n \"Device Info 1\": {\n \"exampleKey1\": \"value1\",\n \"exampleKey2\": \"value2\"\n },\n \"Device Info 2\": {\n \"key1\": \"val1\",\n \"key2\": \"val2\"\n }\n }\n}\n
/services/system/v1/properties/kura
{\n \"kuraProperties\": {\n \"kura.platform\": \"aarch64\",\n \"org.osgi.framework.version\": \"1.10.0\",\n \"kura.user.config\": \"/opt/eclipse/kura/user\",\n \"java.vm.vendor\": \"Temurin\",\n \"kura.name\": \"Eclipse Kura\",\n \"file.command.zip.max.number\": \"1024\",\n \"kura.legacy.ppp.logging.enabled\": \"true\",\n \"kura.tmp\": \"/tmp/.kura\",\n \"kura.packages\": \"/opt/eclipse/kura/packages\",\n \"build.version\": \"buildNumber\",\n \"kura.log.download.journal.fields\": \"SYSLOG_IDENTIFIER,PRIORITY,MESSAGE,STACKTRACE\",\n \"kura.data\": \"/opt/eclipse/kura/data\",\n \"os.name\": \"Linux\",\n \"dpa.read.timeout\": \"60000\",\n \"file.upload.size.max\": \"-1\",\n \"console.device.management.service.ignore\": \"org.eclipse.kura.net.admin.NetworkConfigurationService,org.eclipse.kura.net.admin.FirewallConfigurationService\",\n \"kura.command.user\": \"kura\",\n \"kura.device.name\": \"raspberry\",\n \"kura.partNumber\": \"raspberry\",\n \"kura.project\": \"generic-arm32\",\n \"kura.company\": \"EUROTECH\",\n \"java.home\": \"/usr/lib/jvm/java-8-openjdk-armhf/jre\",\n \"version\": \"5.4.0-SNAPSHOT\",\n \"kura.style.dir\": \"/opt/eclipse/kura/console/skin\",\n \"kura.model.id\": \"raspberry\",\n \"file.separator\": \"/\",\n \"jdk.vendor.version\": \"Zulu 8.70.0.24-SA-linux64\",\n \"kura.model.name\": \"raspberry\",\n \"kura.serialNumber.provider\": \"cat /proc/cpuinfo | grep Serial | cut -d ' ' -f 2\",\n \"kura.have.web.inter\": \"true\",\n \"kura.legacy.bluetooth.beacon.scan\": \"false\",\n \"java.runtime.version\": \"1.8.0_312-8u312-b07-1+rpi1-b07\",\n \"kura.bios.version\": \"N/A\",\n \"kura.marketplace.compatibility.version\": \"KURA_5.4.0-SNAPSHOT\",\n \"kura.framework.config\": \"/opt/eclipse/kura/framework\",\n \"kura.firmware.version\": \"N/A\",\n \"kura.plugins\": \"/opt/eclipse/kura/plugins\",\n \"os.version\": \"6.1.21-v8+ #1642 SMP PREEMPT Mon Apr 3 17:24:16 BST 2023\",\n \"kura.version\": \"KURA_5.4.0-SNAPSHOT\",\n \"org.osgi.framework.vendor\": \"Eclipse\",\n \"java.runtime.name\": \"OpenJDK Runtime Environment\",\n \"kura.log.download.sources\": \"/var/log\",\n \"os.distribution\": \"Linux\",\n \"java.vm.name\": \"OpenJDK Client VM\",\n \"kura.primary.network.interface\": \"eth0\",\n \"kura.home\": \"/opt/eclipse/kura\",\n \"file.command.zip.max.size\": \"100\",\n \"os.arch\": \"arm\",\n \"os.distribution.version\": \"N/A\",\n \"file.upload.in.memory.size.threshold\": \"10240\",\n \"kura.net.virtual.devices.config\": \"unmanaged\",\n \"kura.snapshots\": \"/opt/eclipse/kura/user/snapshots\",\n \"kura.have.net.admin\": \"true\",\n \"java.vm.info\": \"mixed mode\",\n \"java.vm.version\": \"25.312-b07\",\n \"dpa.connection.timeout\": \"60000\",\n \"build.number\": \"generic-arm32-buildNumber\",\n \"ccs.status.notification.url\": \"ccs:log\"\n }\n}\n
This method allows to retrieve framework-related properties by their name. Available properties are in table Framework properties.
/services/system/v1/properties/framework/filter
{\n \"names\": [\"deviceName\", \"numberOfProcessors\", \"kuraHaveNetAdmin\"]\n}\n
"},{"location":"references/rest-apis/rest-system-api/#responses_3","title":"Responses","text":"{\n \"deviceName\": \"RASBPERRY PI 4\",\n \"numberOfProcessors\": 4,\n \"kuraHaveNetAdmin\": true\n}\n
This method allows to retrieve the extended properties and to filter them by group name.
/services/system/v1/properties/extended/filter
{\n \"groupNames\": [\"Device Info 1\"]\n}\n
"},{"location":"references/rest-apis/rest-system-api/#responses_4","title":"Responses","text":"{\n \"extendedProperties\": {\n \"Device Info 1\": {\n \"exampleKey1\": \"value1\",\n \"exampleKey2\": \"value2\"\n }\n }\n}\n
This method allows to retrieve Kura-related properties (derived from the kura.properties
file) and filter by their name. Available properties are listed in the table Kura properties.
/services/system/v1/properties/kura/filter
{\n \"names\": [\"kura.platform\", \"file.upload.size.max\", \"kura.have.net.admin\"]\n}\n
"},{"location":"references/rest-apis/rest-system-api/#responses_5","title":"Responses","text":"{\n \"kuraProperties\": {\n \"kura.platform\": \"aarch64\",\n \"kura.have.net.admin\": \"true\",\n \"file.upload.size.max\": \"-1\"\n }\n}\n
!wget https://raw.githubusercontent.com/mattdibi/eclipsecon-edgeAI-talk/master/notebook/train-data-raw.csv\n!wget https://raw.githubusercontent.com/mattdibi/eclipsecon-edgeAI-talk/master/notebook/train-data-raw.csv
--2022-10-18 15:32:34-- https://raw.githubusercontent.com/mattdibi/eclipsecon-edgeAI-talk/master/notebook/train-data-raw.csv\nResolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.110.133, 185.199.111.133, 185.199.108.133, ...\nConnecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.110.133|:443... connected.\nHTTP request sent, awaiting response... 200 OK\nLength: 13288126 (13M) [text/plain]\nSaving to: \u2018train-data-raw.csv.1\u2019\n\ntrain-data-raw.csv. 100%[===================>] 12,67M 4,56MB/s in 2,8s \n\n2022-10-18 15:32:38 (4,56 MB/s) - \u2018train-data-raw.csv.1\u2019 saved [13288126/13288126]\n\nIn\u00a0[2]: Copied!
!ls *.csv\n!ls *.csv
train-data-raw.csv\n
Let's start taking a look at the content of this dataset, we'll use pandas (Python Data Analysis library) for this.
In\u00a0[3]: Copied!import pandas as pd\n\nraw_data = pd.read_csv(\"./train-data-raw.csv\")\n\nraw_data.head()\nimport pandas as pd raw_data = pd.read_csv(\"./train-data-raw.csv\") raw_data.head() Out[3]: ID TIMESTAMP MAGNET_X TEMP_HUM_timestamp MAGNET_Z MAGNET_Y ACC_Y ACC_X GYRO_Y_timestamp ACC_Z ... PRESSURE_timestamp MAGNET_X_timestamp ACC_X_timestamp GYRO_Z_timestamp HUMIDITY_timestamp assetName ACC_Z_timestamp GYRO_X GYRO_Y GYRO_Z 0 1 1645778791786 -2.680372 1645778791413 5.036951 8.646852 0.004364 0.080122 1645778791413 0.984048 ... 1645778791413 1645778791413 1645778791413 1645778791413 1645778791413 asset-sensehat 1645778791413 0.053243 0.028920 0.036950 1 2 1645778792381 -3.110756 1645778792378 5.952562 10.521458 0.005091 0.080122 1645778792378 0.992090 ... 1645778792378 1645778792378 1645778792378 1645778792378 1645778792378 asset-sensehat 1645778792378 -0.051105 -0.028920 -0.037256 2 3 1645778793412 -3.482263 1645778793408 6.719675 11.944528 0.005334 0.080122 1645778793408 0.986729 ... 1645778793408 1645778793408 1645778793408 1645778793408 1645778793408 asset-sensehat 1645778793408 -0.025253 0.025560 0.038478 3 4 1645778794411 -3.813552 1645778794407 7.375115 13.093461 0.006061 0.080122 1645778794407 0.990384 ... 1645778794407 1645778794407 1645778794407 1645778794407 1645778794407 asset-sensehat 1645778794407 0.100695 -0.023422 -0.037867 4 5 1645778795411 -4.050513 1645778795407 7.854155 14.029530 0.004849 0.080607 1645778795407 0.988922 ... 1645778795407 1645778795407 1645778795407 1645778795407 1645778795407 asset-sensehat 1645778795407 -0.100389 0.021895 0.038172
5 rows \u00d7 29 columns
In\u00a0[4]: Copied!features = ['ACC_Y', 'ACC_X', 'ACC_Z',\n 'PRESSURE', 'TEMP_PRESS', 'TEMP_HUM',\n 'HUMIDITY', 'GYRO_X', 'GYRO_Y', 'GYRO_Z']\n\ndata = raw_data[features]\n\ndata.head()\nfeatures = ['ACC_Y', 'ACC_X', 'ACC_Z', 'PRESSURE', 'TEMP_PRESS', 'TEMP_HUM', 'HUMIDITY', 'GYRO_X', 'GYRO_Y', 'GYRO_Z'] data = raw_data[features] data.head() Out[4]: ACC_Y ACC_X ACC_Z PRESSURE TEMP_PRESS TEMP_HUM HUMIDITY GYRO_X GYRO_Y GYRO_Z 0 0.004364 0.080122 0.984048 992.322998 38.724998 40.330822 19.487146 0.053243 0.028920 0.036950 1 0.005091 0.080122 0.992090 992.288330 38.772915 40.385788 19.465750 -0.051105 -0.028920 -0.037256 2 0.005334 0.080122 0.986729 992.275635 38.795834 40.349144 19.572731 -0.025253 0.025560 0.038478 3 0.006061 0.080122 0.990384 992.279053 38.797916 40.330822 19.358767 0.100695 -0.023422 -0.037867 4 0.004849 0.080607 0.988922 992.333008 38.845833 40.385788 19.390862 -0.100389 0.021895 0.038172 In\u00a0[5]: Copied!
%matplotlib inline\nimport matplotlib.pyplot as plt\n\ndata.hist(bins=50, figsize=(20,15))\nplt.show()\n%matplotlib inline import matplotlib.pyplot as plt data.hist(bins=50, figsize=(20,15)) plt.show()
Note: Some of you might notice that this is a really simple dataset: some of the input data (like GYRO_*
and ACC_*
) do not change much over time. Such a dataset is not very challenging and a few, well-placed, thresholds might be sufficient to spot anomalous behaviour. For this tutorial we decided to keep things simple and easy to replicate. Anomalies can be simply triggered by moving the Raspberry Pi around.
Keep in mind that this approach is generic: any dataset from any appliance/connected device can be processed in the same way we're showing here. That's the magic of neural networks!
In\u00a0[6]: Copied!print(\"Data used in the Triton preprocessor\")\nprint(\"-----------Min-----------\")\nprint(data.min())\nprint(\"-----------Max-----------\")\nprint(data.max())\nprint(\"-------------------------\")\nprint(\"Data used in the Triton preprocessor\") print(\"-----------Min-----------\") print(data.min()) print(\"-----------Max-----------\") print(data.max()) print(\"-------------------------\")
Data used in the Triton preprocessor\n-----------Min-----------\nACC_Y -0.132551\nACC_X -0.049693\nACC_Z 0.759847\nPRESSURE 976.001709\nTEMP_PRESS 38.724998\nTEMP_HUM 40.220890\nHUMIDITY 13.003981\nGYRO_X -1.937896\nGYRO_Y -0.265019\nGYRO_Z -0.250647\ndtype: float64\n-----------Max-----------\nACC_Y 0.093099\nACC_X 0.150289\nACC_Z 1.177543\nPRESSURE 1007.996338\nTEMP_PRESS 46.093750\nTEMP_HUM 48.355824\nHUMIDITY 23.506138\nGYRO_X 1.923712\nGYRO_Y 0.219204\nGYRO_Z 0.671759\ndtype: float64\n-------------------------\nIn\u00a0[7]: Copied!
from sklearn.preprocessing import MinMaxScaler\n\nscaler = MinMaxScaler()\nscaled_data = scaler.fit_transform(data.to_numpy())\nfrom sklearn.preprocessing import MinMaxScaler scaler = MinMaxScaler() scaled_data = scaler.fit_transform(data.to_numpy()) In\u00a0[8]: Copied!
pd.DataFrame(scaled_data).describe()\npd.DataFrame(scaled_data).describe() Out[8]: 0 1 2 3 4 5 6 7 8 9 count 25278.000000 25278.000000 25278.000000 25278.000000 25278.000000 25278.000000 25278.000000 25278.000000 25278.000000 25278.000000 mean 0.603124 0.674196 0.550454 0.526446 0.605576 0.552252 0.466400 0.501160 0.545457 0.271295 std 0.049333 0.015135 0.031627 0.054050 0.288300 0.256587 0.176293 0.062908 0.067678 0.014665 min 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 25% 0.597087 0.667343 0.544924 0.481917 0.501060 0.441442 0.325637 0.501348 0.544670 0.270709 50% 0.603534 0.673413 0.551342 0.521377 0.655357 0.608108 0.511715 0.501841 0.547096 0.271685 75% 0.611055 0.680698 0.555426 0.552892 0.819339 0.734234 0.575212 0.502407 0.549386 0.272577 max 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 In\u00a0[9]: Copied!
from sklearn.model_selection import train_test_split\nimport numpy as np\n\nx_train, x_test = train_test_split(scaled_data, test_size=0.3, random_state=42)\nx_train = x_train.astype(np.float32)\nx_test = x_test.astype(np.float32)\nfrom sklearn.model_selection import train_test_split import numpy as np x_train, x_test = train_test_split(scaled_data, test_size=0.3, random_state=42) x_train = x_train.astype(np.float32) x_test = x_test.astype(np.float32) In\u00a0[10]: Copied!
import os\nos.environ['TF_CPP_MIN_LOG_LEVEL']='2' # Avoid AVX2 error\n\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import Input, Dense, Dropout\n\ndef create_model(input_dim):\n # The encoder will consist of a number of dense layers that decrease in size\n # as we taper down towards the bottleneck of the network, the latent space\n input_data = Input(shape=(input_dim,), name='INPUT0')\n\n # hidden layers\n encoder = Dense(9, activation='tanh', name='encoder_1')(input_data)\n encoder = Dropout(.15)(encoder)\n encoder = Dense(6, activation='tanh', name='encoder_2')(encoder)\n encoder = Dropout(.15)(encoder)\n\n # bottleneck layer\n latent_encoding = Dense(3, activation='linear', name='latent_encoding')(encoder)\n\n # The decoder network is a mirror image of the encoder network\n decoder = Dense(6, activation='tanh', name='decoder_1')(latent_encoding)\n decoder = Dropout(.15)(decoder)\n decoder = Dense(9, activation='tanh', name='decoder_2')(decoder)\n decoder = Dropout(.15)(decoder)\n\n # The output is the same dimension as the input data we are reconstructing\n reconstructed_data = Dense(input_dim, activation='linear', name='OUTPUT0')(decoder)\n\n autoencoder_model = Model(input_data, reconstructed_data)\n\n return autoencoder_model\nimport os os.environ['TF_CPP_MIN_LOG_LEVEL']='2' # Avoid AVX2 error from tensorflow.keras.models import Model from tensorflow.keras.layers import Input, Dense, Dropout def create_model(input_dim): # The encoder will consist of a number of dense layers that decrease in size # as we taper down towards the bottleneck of the network, the latent space input_data = Input(shape=(input_dim,), name='INPUT0') # hidden layers encoder = Dense(9, activation='tanh', name='encoder_1')(input_data) encoder = Dropout(.15)(encoder) encoder = Dense(6, activation='tanh', name='encoder_2')(encoder) encoder = Dropout(.15)(encoder) # bottleneck layer latent_encoding = Dense(3, activation='linear', name='latent_encoding')(encoder) # The decoder network is a mirror image of the encoder network decoder = Dense(6, activation='tanh', name='decoder_1')(latent_encoding) decoder = Dropout(.15)(decoder) decoder = Dense(9, activation='tanh', name='decoder_2')(decoder) decoder = Dropout(.15)(decoder) # The output is the same dimension as the input data we are reconstructing reconstructed_data = Dense(input_dim, activation='linear', name='OUTPUT0')(decoder) autoencoder_model = Model(input_data, reconstructed_data) return autoencoder_model In\u00a0[11]: Copied!
autoencoder_model = create_model(len(features))\nautoencoder_model.summary()\nautoencoder_model = create_model(len(features)) autoencoder_model.summary()
Model: \"model\"\n_________________________________________________________________\n Layer (type) Output Shape Param # \n=================================================================\n INPUT0 (InputLayer) [(None, 10)] 0 \n \n encoder_1 (Dense) (None, 9) 99 \n \n dropout (Dropout) (None, 9) 0 \n \n encoder_2 (Dense) (None, 6) 60 \n \n dropout_1 (Dropout) (None, 6) 0 \n \n latent_encoding (Dense) (None, 3) 21 \n \n decoder_1 (Dense) (None, 6) 24 \n \n dropout_2 (Dropout) (None, 6) 0 \n \n decoder_2 (Dense) (None, 9) 63 \n \n dropout_3 (Dropout) (None, 9) 0 \n \n OUTPUT0 (Dense) (None, 10) 100 \n \n=================================================================\nTotal params: 367\nTrainable params: 367\nNon-trainable params: 0\n_________________________________________________________________\nIn\u00a0[12]: Copied!
from tensorflow.keras import optimizers\n\nbatch_size = 32\nmax_epochs = 15\nlearning_rate = .0001\n\nopt = optimizers.Adam(learning_rate=learning_rate)\nautoencoder_model.compile(optimizer=opt, loss='mse', metrics=['accuracy'])\ntrain_history = autoencoder_model.fit(x_train, x_train,\n shuffle=True,\n epochs=max_epochs,\n batch_size=batch_size,\n validation_data=(x_test, x_test))\nfrom tensorflow.keras import optimizers batch_size = 32 max_epochs = 15 learning_rate = .0001 opt = optimizers.Adam(learning_rate=learning_rate) autoencoder_model.compile(optimizer=opt, loss='mse', metrics=['accuracy']) train_history = autoencoder_model.fit(x_train, x_train, shuffle=True, epochs=max_epochs, batch_size=batch_size, validation_data=(x_test, x_test))
Epoch 1/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.2282 - accuracy: 0.1129 - val_loss: 0.0922 - val_accuracy: 0.0045\nEpoch 2/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0949 - accuracy: 0.1541 - val_loss: 0.0279 - val_accuracy: 0.4210\nEpoch 3/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0613 - accuracy: 0.1779 - val_loss: 0.0206 - val_accuracy: 0.4426\nEpoch 4/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0466 - accuracy: 0.2152 - val_loss: 0.0186 - val_accuracy: 0.5276\nEpoch 5/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0366 - accuracy: 0.2514 - val_loss: 0.0157 - val_accuracy: 0.5944\nEpoch 6/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0290 - accuracy: 0.3083 - val_loss: 0.0119 - val_accuracy: 0.6403\nEpoch 7/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0228 - accuracy: 0.3930 - val_loss: 0.0078 - val_accuracy: 0.7182\nEpoch 8/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0186 - accuracy: 0.4668 - val_loss: 0.0059 - val_accuracy: 0.8195\nEpoch 9/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0157 - accuracy: 0.5021 - val_loss: 0.0048 - val_accuracy: 0.8256\nEpoch 10/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0136 - accuracy: 0.5277 - val_loss: 0.0042 - val_accuracy: 0.8263\nEpoch 11/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0121 - accuracy: 0.5409 - val_loss: 0.0037 - val_accuracy: 0.8296\nEpoch 12/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0107 - accuracy: 0.5569 - val_loss: 0.0036 - val_accuracy: 0.8306\nEpoch 13/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0098 - accuracy: 0.5857 - val_loss: 0.0034 - val_accuracy: 0.8256\nEpoch 14/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0089 - accuracy: 0.6076 - val_loss: 0.0033 - val_accuracy: 0.8281\nEpoch 15/15\n553/553 [==============================] - 1s 1ms/step - loss: 0.0083 - accuracy: 0.6337 - val_loss: 0.0032 - val_accuracy: 0.8262\nIn\u00a0[13]: Copied!
plt.plot(train_history.history['loss'])\nplt.plot(train_history.history['val_loss'])\nplt.legend(['loss on train data', 'loss on test data'])\nplt.plot(train_history.history['loss']) plt.plot(train_history.history['val_loss']) plt.legend(['loss on train data', 'loss on test data']) Out[13]:
<matplotlib.legend.Legend at 0x16d0c3400>
Here we can see the loss for the training set and the test set on the epochs.
Some of you might notice that this graph is somewhat unexpected. Why the validation loss is lower than the train loss? This is the effect of the regularization: regularization terms and dropout layer are affecting the network during training. A good writeup of this effect can be found here.
As an excercise try and compute the average MSE on the training set and the test set. You'll find that the MSE is lower in the training set!
We can now save the model on disk as we'll use this later.
In\u00a0[14]: Copied!autoencoder_model.save(\"./saved_model/autoencoder\")\nautoencoder_model.save(\"./saved_model/autoencoder\")
WARNING:absl:Function `_wrapped_model` contains input name(s) INPUT0 with unsupported characters which will be renamed to input0 in the SavedModel.\n
INFO:tensorflow:Assets written to: ./saved_model/autoencoder/assets\n
INFO:tensorflow:Assets written to: ./saved_model/autoencoder/assets\nIn\u00a0[15]: Copied!
!ls ./saved_model/autoencoder\n!ls ./saved_model/autoencoder
assets keras_metadata.pb saved_model.pb variables\nIn\u00a0[16]: Copied!
input_sample = x_test[3:4].copy() # Deep copy\n\nreconstructed_sample = autoencoder_model.predict(input_sample)\n\nprint(input_sample)\nprint(reconstructed_sample)\ninput_sample = x_test[3:4].copy() # Deep copy reconstructed_sample = autoencoder_model.predict(input_sample) print(input_sample) print(reconstructed_sample)
1/1 [==============================] - 0s 109ms/step\n[[0.603534 0.6770555 0.54900813 0.5327966 0.6680801 0.6171171\n 0.5198642 0.50135666 0.54716927 0.2718224 ]]\n[[0.59638697 0.67410123 0.5484349 0.52024144 0.64766663 0.5916597\n 0.4445051 0.499677 0.54471916 0.26904327]]\nIn\u00a0[17]: Copied!
import matplotlib.pyplot as plt\n\nindex = np.arange(10)\nbar_width = 0.35\n\nfigure, ax = plt.subplots()\n\ninbar = ax.bar(index, input_sample[0], bar_width, label=\"Input data\")\nrecbar = ax.bar(index+bar_width, reconstructed_sample[0], bar_width, label=\"Reconstruced data\")\n\nax.set_xlabel('Features')\nax.set_xticks(index + bar_width / 2)\nax.set_xticklabels(features, rotation = 45)\nax.legend()\nimport matplotlib.pyplot as plt index = np.arange(10) bar_width = 0.35 figure, ax = plt.subplots() inbar = ax.bar(index, input_sample[0], bar_width, label=\"Input data\") recbar = ax.bar(index+bar_width, reconstructed_sample[0], bar_width, label=\"Reconstruced data\") ax.set_xlabel('Features') ax.set_xticks(index + bar_width / 2) ax.set_xticklabels(features, rotation = 45) ax.legend() Out[17]:
<matplotlib.legend.Legend at 0x16d184880>
As we can see from the graph above it reconstructed the input fairly well. It is not perfect since the Autoencoder is lossy but it is good enough
What happens if we manipulate this sample in a way the autoencoder doesn't expect (i.e. we introduce an anomaly)?
Let's try and set the ACC_Z
to a value the autoencoder has never seen before.
input_anomaly = input_sample.copy() # Deep copy\n\ninput_anomaly[0][2] = 0.15\n\nreconstructed_anomaly = autoencoder_model.predict(input_anomaly)\n\nprint(input_anomaly)\nprint(reconstructed_anomaly)\ninput_anomaly = input_sample.copy() # Deep copy input_anomaly[0][2] = 0.15 reconstructed_anomaly = autoencoder_model.predict(input_anomaly) print(input_anomaly) print(reconstructed_anomaly)
1/1 [==============================] - 0s 21ms/step\n[[0.603534 0.6770555 0.15 0.5327966 0.6680801 0.6171171\n 0.5198642 0.50135666 0.54716927 0.2718224 ]]\n[[0.60162103 0.69035804 0.55594885 0.51874125 0.7346029 0.6700014\n 0.40932336 0.5034408 0.5424664 0.26861513]]\nIn\u00a0[19]: Copied!
figure, ax = plt.subplots()\n\ninbar = ax.bar(index, input_anomaly[0], bar_width, label=\"Input anomaly\")\nrecbar = ax.bar(index+bar_width, reconstructed_anomaly[0], bar_width, label=\"Reconstruced anomaly\")\n\nax.set_xlabel('Features')\nax.set_xticks(index + bar_width / 2)\nax.set_xticklabels(features, rotation = 45)\nax.legend()\nfigure, ax = plt.subplots() inbar = ax.bar(index, input_anomaly[0], bar_width, label=\"Input anomaly\") recbar = ax.bar(index+bar_width, reconstructed_anomaly[0], bar_width, label=\"Reconstruced anomaly\") ax.set_xlabel('Features') ax.set_xticks(index + bar_width / 2) ax.set_xticklabels(features, rotation = 45) ax.legend() Out[19]:
<matplotlib.legend.Legend at 0x16d3c0220>
The autoencoder fails to reconstruct the data it received at the input. This means that the reconstruction error is very high.
In\u00a0[20]: Copied!from sklearn.metrics import mean_squared_error\n\nprint(\"Anomaly %f\"% mean_squared_error(input_anomaly[0], reconstructed_anomaly[0]))\nprint(\"Normal %f\"% mean_squared_error(input_sample[0], reconstructed_sample[0]))\nfrom sklearn.metrics import mean_squared_error print(\"Anomaly %f\"% mean_squared_error(input_anomaly[0], reconstructed_anomaly[0])) print(\"Normal %f\"% mean_squared_error(input_sample[0], reconstructed_sample[0]))
Anomaly 0.018465\nNormal 0.000698\n
It's working as expected!
We now need to decide when to trigger an alarm (i.e. classify an input sample as anomalous) from this reconstruction error. In other words we need to decide our threshold.
There are multiple ways to set this value, in this example we'll use the Z-Score.
From Wikipedia:
In statistics, the standard score is the number of standard deviations by which the value of a raw score (i.e., an observed value or data point) is above or below the mean value of what is being observed or measured.[...]
It is calculated by subtracting the population mean from an individual raw score and then dividing the difference by the population standard deviation.
We'll consider a sample an anomaly if the Reconstruction Error Z-Score is not in the range [-2, +2]. This means that if the reconstruction error for a sample is more than 2 standard deviation away from the average reconstruction error computed on the test set, the sample is an anomaly. This choice is arbirtary, we can control the sensitivity of the detector by changing this range.
In\u00a0[21]: Copied!x_test_recon = autoencoder_model.predict(x_test)\nreconstruction_scores = np.mean((x_test - x_test_recon)**2, axis=1) # MSE\n\nreconstruction_scores_pd = pd.DataFrame({'recon_score': reconstruction_scores})\nprint(reconstruction_scores_pd.describe())\nx_test_recon = autoencoder_model.predict(x_test) reconstruction_scores = np.mean((x_test - x_test_recon)**2, axis=1) # MSE reconstruction_scores_pd = pd.DataFrame({'recon_score': reconstruction_scores}) print(reconstruction_scores_pd.describe())
237/237 [==============================] - 0s 620us/step\n recon_score\ncount 7584.000000\nmean 0.003175\nstd 0.005438\nmin 0.000098\n25% 0.000816\n50% 0.001211\n75% 0.002108\nmax 0.106237\nIn\u00a0[22]: Copied!
def z_score(mse_sample):\n return (mse_sample - reconstruction_scores_pd.mean())/reconstruction_scores_pd.std()\ndef z_score(mse_sample): return (mse_sample - reconstruction_scores_pd.mean())/reconstruction_scores_pd.std() In\u00a0[23]: Copied!
mse_anomaly = mean_squared_error(input_anomaly[0], reconstructed_anomaly[0])\nmse_normal = mean_squared_error(input_sample[0], reconstructed_sample[0])\n\nz_score_anomaly = z_score(mse_anomaly)\nz_score_normal = z_score(mse_normal)\n\nprint(\"Anomaly Z-score %f\"% z_score_anomaly)\nprint(\"Normal Z-score %f\"% z_score_normal)\nmse_anomaly = mean_squared_error(input_anomaly[0], reconstructed_anomaly[0]) mse_normal = mean_squared_error(input_sample[0], reconstructed_sample[0]) z_score_anomaly = z_score(mse_anomaly) z_score_normal = z_score(mse_normal) print(\"Anomaly Z-score %f\"% z_score_anomaly) print(\"Normal Z-score %f\"% z_score_normal)
Anomaly Z-score 2.811887\nNormal Z-score -0.455488\n
We now have our anomaly detector... let's see how we can deploy it on our Kura\u2122-powered edge device.
In\u00a0[24]: Copied!!rm -rf ./tf_autoencoder_fp32/ && mkdir -p ./tf_autoencoder_fp32/1\n!rm -rf ./tf_autoencoder_fp32/ && mkdir -p ./tf_autoencoder_fp32/1 In\u00a0[25]: Copied!
!ls\n!ls
AD-EdgeAI.ipynb requirements.txt train-data-raw.csv\nREADME.md saved_model train-data-raw.csv.1\nimgs tf_autoencoder_fp32\nIn\u00a0[26]: Copied!
cp -r ./saved_model/autoencoder tf_autoencoder_fp32/1/model.savedmodel\ncp -r ./saved_model/autoencoder tf_autoencoder_fp32/1/model.savedmodel In\u00a0[27]: Copied!
!tree tf_autoencoder_fp32\n!tree tf_autoencoder_fp32
tf_autoencoder_fp32\n\u2514\u2500\u2500 1\n \u2514\u2500\u2500 model.savedmodel\n \u251c\u2500\u2500 assets\n \u251c\u2500\u2500 keras_metadata.pb\n \u251c\u2500\u2500 saved_model.pb\n \u2514\u2500\u2500 variables\n \u251c\u2500\u2500 variables.data-00000-of-00001\n \u2514\u2500\u2500 variables.index\n\n4 directories, 4 files\n
Now comes the hard part: we need to provide the model configuration (i.e. the config.pbtxt
file). In the case of the autoencoder is pretty simple:
name: \"tf_autoencoder_fp32\"\nbackend: \"tensorflow\"\nmax_batch_size: 0\ninput [\n {\n name: \"INPUT0\"\n data_type: TYPE_FP32\n dims: [ 1, 10 ]\n }\n]\noutput [\n {\n name: \"OUTPUT0\"\n data_type: TYPE_FP32\n dims: [ -1, 10 ]\n }\n]\nversion_policy: { all { }}\ninstance_group [{ kind: KIND_CPU }]\n
Each model input
and output
must specify the name
, data_type
and dims
. We already know all of these:
name
: corresponds to the layer name we've seen in the Model Training section. INPUT0
for the input and OUTPUT0
for the output.data_type
: will be float since we didn't perform any quantizationdims
: is the shape of the in/out tensor. In this case it will correspond to an array with the same length as the number of features.Other interesting parameters of this configuration are:
backend
: where we set the backend for the model. In this case it will be the Tensorflow backendname
: the name of the model that must correspond to the name of the folderinstance_group
: where we set where we want the model to run. In this case we'll use the CPU since we're on a Raspberry Pi but keep in mind that Triton support multiple accelerators.for a deep dive into the model configuration parameter take a look at the official documentation.
"},{"location":"tutorials/AD-EdgeAI/#edge-ai-anomaly-detection","title":"Edge AI Anomaly Detection\u00b6","text":""},{"location":"tutorials/AD-EdgeAI/#overview","title":"Overview\u00b6","text":"This document contains the code and the instructions for our EclipseCON 2022 Talk: \"How to Train Your Dragon and Its Friends: AI on the Edge with Eclipse Kura\u2122\"
This notebook can also be viewed and ran on Google Colab.
In this example scenario we will collect the data provided by a Raspberry Pi Sense HAT using Eclipse Kura\u2122 and upload them to a Eclipse Kapua\u2122 instance. We will then download this data and train an AI-based anomaly detector using TensorFlow. Finally we will deploy the trained anomaly detector model leveraging Nvidia Triton\u2122 Inference Server and Eclipse Kura\u2122 integration.
We'll subdivide this example scenario in three main sections:
In this setup we'll leverage Eclipe Kura\u2122 and Kapua\u2122 for retrieving data from a Raspberry Pi Sense HAT and upload them to the cloud.
The Sense HAT is an add-on board for Raspberry Pi which provides an 8\u00d78 RGB LED matrix, a five-button joystick and includes the following sensors:
Requirement: A Raspberry Pi 3/4 running the latest version of Raspberry Pi OS 64 bit.
To make everything work on the Raspberry Pi we need to use the develop
version of the raspberry-pi-ubuntu-20-nn
Kura installer (yes, I know we're installing the Ubuntu package on the Raspberry Pi OS but bear with me...) . You can do so by downloading the repo and building locally or by downloading a pre-built installer from the Kura CI artifacts.
Copy the resulting file kura_<version>_raspberry-pi-ubuntu-20_installer-nn.deb
on the target device.
On the target device run the following commands:
sudo apt-get install -y wget apt-transport-https gnupg\n
sudo wget -O - https://packages.adoptium.net/artifactory/api/gpg/key/public | sudo apt-key add -\n
sudo echo \"deb https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main\" | sudo tee /etc/apt/sources.list.d/adoptium.list\n
sudo apt-get update && sudo apt-get install temurin-8-jdk chrony\n
Finally install Kura with:
sudo apt install ./kura_<version>_raspberry-pi-ubuntu-20_installer-nn.deb\n"},{"location":"tutorials/AD-EdgeAI/#cloud-connection","title":"Cloud connection\u00b6","text":"
After setting up an Eclipse Kura\u2122 instance on the Raspberry Pi we'll need to connect it to an Eclipse Kapua\u2122 instance.
An excellent tutorial on how to deploy a Kapua\u2122 instance using Docker is available in the official repository. For the purpose of this tutorial we'll assume a Kapua\u2122 instance is already running and is available for connection from Kura\u2122
After setting up the Kapua\u2122 instance you can refer to the official Kura\u2122 documentation for connecting the Raspberry Pi to the Kapua\u2122 instance. For the remaining of this tutorial we'll assume a connection with the Kapua\u2122 was correctly established.
"},{"location":"tutorials/AD-EdgeAI/#data-publisher","title":"Data publisher\u00b6","text":"To publish the collected data on the Cloud we'll need to create a new Cloud Publisher through the Kura\u2122 web interface. Go to \"Cloud Connections\" and press \"New Pub/Sub\", in the example below we'll call our new publisher KapuaSenseHatPublisher
.
To keep things clean we'll create a new topic called SenseHat
. To do so we'll move to the KapuaSenseHatPublisher
configuration and we'll update the Application Topic
field to A1/SenseHat
Kura\u2122 provides a driver that allows to interact to a RaspberryPi SenseHat device using Kura Driver, Asset and Wires frameworks.
From the Kura\u2122 documentation:
Eclipse Kura introduces a model based on the concepts of Drivers and Assets to simplify the communication with the field devices attached to a gateway.
A Driver encapsulates the communication protocol and its configuration parameters, dealing with the low-level characteristics of the field protocol. It opens, closes and performs the communication with the end field device. It also exposes field protocol specific information that can be used by upper levels of abstraction to simplify the interaction with the end devices.
An Asset is a logical representation of a field device, described by a list of Channels. The Asset uses a specific Driver instance to communicate with the underlying device and it models a generic device resource as a Channel. A register in a PLC or a GATT Characteristic in a Bluetooth device are examples of Channels. In this way, each Asset has multiple Channels for reading and writing data from/to an Industrial Device.
The Kura Sense Hat driver requires a few changes on the Raspberry Pi:
sudo raspi-config
As others Drivers supported by Kura, it is distributed as a deployment package on the Eclipse Marketplace. It consists of two packages:
We need to install both. Complete installation instructions are available here.
"},{"location":"tutorials/AD-EdgeAI/#driver-configuration","title":"Driver configuration\u00b6","text":"We now need to configure the driver to access the sensors on the SenseHat. Move to the \"Driver and Assets\" section of the web UI and create a new driver. We'll call it driver-sensehat
.
Then add a new Asset (which we'll call asset-sensehat
) to this driver and configure it as per the screenshots below. We'll need a Channel for every sensor we want to access.
Refer to the following table for the driver parameters:
name type value.type resource ACC_X READ FLOAT ACCELERATION_X ACC_Y READ FLOAT ACCELERATION_Y ACC_Z READ FLOAT ACCELERATION_Z GYRO_X READ FLOAT GYROSCOPE_X GYRO_Y READ FLOAT GYROSCOPE_Y GYRO_Z READ FLOAT GYROSCOPE_Z HUMIDITY READ FLOAT HUMIDITY PRESSURE READ FLOAT PRESSURE TEMP_HUM READ FLOAT TEMPERATURE_FROM_HUMIDITY TEMP_PRESS READ FLOAT TEMPERATURE_FROM_PRESSUREAfter correctly configuring it you should see the data in the \"Data\" page of the UI.
"},{"location":"tutorials/AD-EdgeAI/#wire-graph","title":"Wire graph\u00b6","text":"Now that we have our Driver and Cloud Publisher ready we can put everything together with a Kura Wire Graph.
From Kura\u2122 documentation:
The Kura\u2122 Wires feature aims to simplify the development of IoT Edge Computing Applications leveraging reusable configurable components that can be wired together and which, eventually, allows configurable cooperation between these components.
In the dataflow programming model, the application logic is expressed as a directed graph (flow) where each node can have inputs, outputs, and independent processing units. There are nodes that only produce outputs and ones that only consume inputs, which usually represent the start and the end of the flow. The inner-graph nodes process the inputs and produce outputs for downstream nodes. The processing unit of a node executes independently and does not affect the execution of other nodes. Thus, the nodes are highly reusable and portable.
Move to the \"Wire Graph\" section of the UI. We'll need a graph with three components:
Timer
which will dictate the sample rate at which we will collect data coming from the Sense HatWireAsset
for the Sense Hat driver assetPublisher
for the Kapua publisher we created before.The resulting Wire Graph will look like this:
"},{"location":"tutorials/AD-EdgeAI/#timer","title":"Timer\u00b6","text":"Configure the timer such that it will poll the SenseHat each second, this can be done by setting the simple.interval
to 1
.
Select the driver-sensehat
when creating the WireAsset. No further configuration is needed for this component.
Create a \"Publisher\" Wire component and select the KapuaSensehatPublisher
from the target filter.
Don't forget to press \"Apply\" to start the Wire Graph!
"},{"location":"tutorials/AD-EdgeAI/#collect-the-data","title":"Collect the data\u00b6","text":"At this point you should see data coming from the Rasperry Pi from the Kapua\u2122 console under the SenseHat
topic.
You can download the .csv
file directly from the console using the \"Export to CSV\" button.
We will now use the data collected in the previous section to train an artificial neural network-based Anomaly Detector of our design. To this end we will use an Autoencoder model. To understand why we choose such model we need to understand how it works. From Wikipedia:
An autoencoder is a type of artificial neural network used to learn efficient codings of unlabeled data (unsupervised learning). The encoding is validated and refined by attempting to regenerate the input from the encoding. The autoencoder learns a representation (encoding) for a set of data, typically for dimensionality reduction, by training the network to ignore insignificant data (\u201cnoise\u201d).
Another application for autoencoders is anomaly detection. By learning to replicate the most salient features in the training data [...] the model is encouraged to learn to precisely reproduce the most frequently observed characteristics. When facing anomalies, the model should worsen its reconstruction performance. In most cases, only data with normal instances are used to train the autoencoder; in others, the frequency of anomalies is small compared to the observation set so that its contribution to the learned representation could be ignored. After training, the autoencoder will accurately reconstruct \"normal\" data, while failing to do so with unfamiliar anomalous data. Reconstruction error (the error between the original data and its low dimensional reconstruction) is used as an anomaly score to detect anomalies
In simple terms:
Why did we choose this approach over others?
We can now work on our .csv
file downloaded from Kapua. For demonstration purposes an already available dataset is provided within this repository.
If you're running this notebook through Google Colab you'll need to download the dataset running the cell below:
"},{"location":"tutorials/AD-EdgeAI/#feature-selection","title":"Feature selection\u00b6","text":"As you might notice there's some information in the dataset we don't care about and are not meaningful for our application:
ID
timestamps
assetName
which doesn't changeThen we can remove them from the dataset.
"},{"location":"tutorials/AD-EdgeAI/#feature-scaling","title":"Feature scaling\u00b6","text":"AI models don't perform well when the input numerical attributes have very different scales. As you can see ACC_X
, ACC_Y
and ACC_Z
range from 0 to 1, while the PRESSURE
have far higher values.
There are two common ways to address this: normalization and standardization.
Normalization (a.k.a. Min-max scaling) shifts and rescales values so that they end up ranging from 0 to 1. This can be done by subtracting the min value and dividing by the max minus the min.
x' = $\\frac{x - min(x)}{max(x) - min(x)}$
Standardization makes the values of each feature in the data have zero-mean (when subtracting the mean in the numerator) and unit-variance. The general method of calculation is to determine the distribution mean and standard deviation for each feature. Next we subtract the mean from each feature. Then we divide the values (mean is already subtracted) of each feature by its standard deviation.
x' = $\\frac{x - avg(x)}{\\sigma}$
Fortunately for us scikit-learn library provides a function for both of them. In this case we'll use normalization because it works well for this application.
"},{"location":"tutorials/AD-EdgeAI/#train-test-split","title":"Train test split\u00b6","text":"The only way to know how well a model will generalize to new data points is to try it on new data. To do so we split our data into two sets: the training set and the test set.
To do so we'll use a function from scikit-learn
.
We can now leverage the Keras API of Tensorflow for creating our Autoencoder and then train it on our dataset.
We'll design a neural network architecture such that we impose a bottleneck in the network which forces a compressed knowledge representation of the original input (also called the latent-space representation). If the input features were each independent of one another, this compression and subsequent reconstruction would be a very difficult task. However, if some sort of structure exists in the data (ie. correlations between input features), this structure can be learned and consequently leveraged when forcing the input through the network's bottleneck.
The bottleneck consists of reducing the number of neurons for each layer of the neural network up to a certain point, and then increase the number until the original input number is reached. This will result in a hourglass shape which is typical for the Autoencoders.
"},{"location":"tutorials/AD-EdgeAI/#build-the-autoencoder-model","title":"Build the Autoencoder model\u00b6","text":"In this example we'll use a basic fully-connected autoencoder but keep in mind that autoencoders can be built with different classes of neural network (i.e. Convolutional Neural Networks, Recurrent Neural Networks etc).
"},{"location":"tutorials/AD-EdgeAI/#model-training","title":"Model training\u00b6","text":"As we already explained, the autoencoder is a type of artificial neural network used to learn efficient codings of unlabeled data. We'll use that to reconstruct the input at the output. To train an autoencoder we don\u2019t need to do anything fancy, just throw the raw input data at it. Autoencoders are considered an unsupervised learning technique since they don\u2019t need explicit labels to train on but to be more precise they are self-supervised because they generate their own labels from the training data.
To train our neural network we need to have a performance metric to measure how well it is learning to reconstruct the data i.e. our loss function. The loss function in our example, which we need to minimize during our training, is the error between the input data and the data reconstructed by the autoencoder. We'll use the Mean Squared Error.
MSE = $\\frac{1}{n}\\sum_{i=1}^{n}{(Y_i - Y'_i)^2}$
Where:
Before starting the training we need to set the hyperparameters). Hyperparameters are parameters whose values control the learning process and determine the values of model parameters that a learning algorithm ends up learning. These are the learning_rate
, max_epochs
, optimizer
and the batch_size
you see in the code snippet below. You may ask yourself how to set them, it all comes down to trial and error. Try tweaking them below and see how they affect the learning process...
A good explaination of their meaning can be found in the Keras documentation.
"},{"location":"tutorials/AD-EdgeAI/#model-evaluation","title":"Model evaluation\u00b6","text":"We now have a model that reconstruct the input at the output... doesn't sounds really useful right?
Let's see it in action. Let's take a sample from the test set and run it through our autoencoder.
"},{"location":"tutorials/AD-EdgeAI/#model-deployment","title":"Model deployment\u00b6","text":"To deploy our model on the target device we'll leverage Kura\u2122's newly added Nvidia\u2122 Triton Inferece Server integration.
The Nvidia\u2122 Triton Inference Server is an open-source inference service software that enables the user to deploy trained AI models from any framework on GPU or CPU infrastructure. It supports all major frameworks like TensorFlow, TensorRT, PyTorch, ONNX Runtime, and even custom framework backend. With specific backends, it is also possible to run Python scripts, mainly for pre-and post-processing purposes, and exploit the DALI building block for optimized operations.
For installation refer to the official Kura\u2122 and Triton documentation. For the rest of this tutorial we'll assume a Triton container is available on the target device. It can be simply installed with:
docker pull nvcr.io/nvidia/tritonserver:22.07-tf2-python-py3\n
We'll also need to install Kura\u2122's Triton bundles:
The first step in using Triton to serve your models is to place one or more models into a model repository i.e. a folder were the model are available for Triton to load. Depending on the type of the model and on what Triton capabilities you want to enable for the model, you may need to create a model configuration for the model. This configuration is a protobuf containing informations about runtime configuration and input/output shape accepted by the model.
For our autoencoder model we'll need three \"models\":
To simplify the handling of these models and improve inference performance, we'll use an advanced feature of Triton wich is an Ensemble Model. From Triton official documentation:
An ensemble model represents a pipeline of one or more models and the connection of input and output tensors between those models. Ensemble models are intended to be used to encapsulate a procedure that involves multiple models, such as \"data preprocessing -> inference -> data postprocessing\". Using ensemble models for this purpose can avoid the overhead of transferring intermediate tensors and minimize the number of requests that must be sent to Triton.
"},{"location":"tutorials/AD-EdgeAI/#autoencoder","title":"Autoencoder\u00b6","text":"As seen in the \"Model training\" section, our model is available as a Tensorflow SavedModel which can be simply loaded by the Triton Tensorflow backend. We just need to configure it properly.
We'll start by creating the following folder structure
tf_autoencoder_fp32\n\u251c\u2500\u2500 1\n\u2502 \u2514\u2500\u2500 model.savedmodel\n\u2502 \u251c\u2500\u2500 assets\n\u2502 \u251c\u2500\u2500 keras_metadata.pb\n\u2502 \u251c\u2500\u2500 saved_model.pb\n\u2502 \u2514\u2500\u2500 variables\n\u2502 \u251c\u2500\u2500 variables.data-00000-of-00001\n\u2502 \u2514\u2500\u2500 variables.index\n\u2514\u2500\u2500 config.pbtxt\n
This can be done by copying the model we saved in the Model Training section:
"},{"location":"tutorials/AD-EdgeAI/#preprocessor","title":"Preprocessor\u00b6","text":"As discussed in the \"Data processing\" section, before providing the incoming data to the autoencoder, we need to perform feature selection and scaling. In addition to these responsibilites, the Preprocessor will need to perform a sort of serialization of the data to comply to the input shape accepted by the Autoencoder. This is due to how Kura manages the data running on Wires. More details can be found here.
To perform all of this we'll use the Python backend available in Triton.
As described in the previous section we will need to provide the following folder structure:
preprocessor\n\u251c\u2500\u2500 1\n\u2502 \u2514\u2500\u2500 model.py\n\u2514\u2500\u2500 config.pbtxt\n
"},{"location":"tutorials/AD-EdgeAI/#preprocessor-configuration","title":"Preprocessor Configuration\u00b6","text":"As discussed in the official Kura documentation:
The AI wire component takes a WireEnvelope as an input, it processes its records and feeds them to the specified preprocessing or inference model.
...
The models that manage the input and the output must expect a list of inputs such that:
WireRecord
properties[1]
Therefore for our input
we'll have that each name corresponds to the names we've seen in the Data Collection section. The output
needs to correspond to the input accepted by the model (i.e. INPUT0
).
name: \"preprocessor\"\nbackend: \"python\"\n\ninput [\n {\n name: \"ACC_X\"\n data_type: TYPE_FP32\n dims: [ 1 ]\n }\n]\ninput [\n {\n name: \"ACC_Y\"\n data_type: TYPE_FP32\n dims: [ 1 ]\n }\n]\n ...\ninput [\n {\n name: \"TEMP_PRESS\"\n data_type: TYPE_FP32\n dims: [ 1 ]\n }\n]\noutput [\n {\n name: \"INPUT0\"\n data_type: TYPE_FP32\n dims: [ 1, 10 ]\n }\n]\ninstance_group [{ kind: KIND_CPU }]\n"},{"location":"tutorials/AD-EdgeAI/#preprocessor-model","title":"Preprocessor Model\u00b6","text":"
As we've seen in the Data Processing section the Preprocessor is responsible for scaling the input features and serializing them in the tensor shape expected by the Autoencoder model.
This can be done with the following python script:
import numpy as np\nimport json\n\nimport triton_python_backend_utils as pb_utils\n\n\nclass TritonPythonModel:\n\n def initialize(self, args):\n self.model_config = model_config = json.loads(args['model_config'])\n\n output0_config = pb_utils.get_output_config_by_name(\n model_config, \"INPUT0\")\n\n self.output0_dtype = pb_utils.triton_string_to_numpy(\n output0_config['data_type'])\n\n def execute(self, requests):\n output0_dtype = self.output0_dtype\n\n responses = []\n\n for request in requests:\n acc_x = pb_utils.get_input_tensor_by_name(request, \"ACC_X\").as_numpy()\n acc_y = pb_utils.get_input_tensor_by_name(request, \"ACC_Y\").as_numpy()\n acc_z = pb_utils.get_input_tensor_by_name(request, \"ACC_Z\").as_numpy()\n gyro_x = pb_utils.get_input_tensor_by_name(request, \"GYRO_X\").as_numpy()\n gyro_y = pb_utils.get_input_tensor_by_name(request, \"GYRO_Y\").as_numpy()\n gyro_z = pb_utils.get_input_tensor_by_name(request, \"GYRO_Z\").as_numpy()\n humidity = pb_utils.get_input_tensor_by_name(request, \"HUMIDITY\").as_numpy()\n pressure = pb_utils.get_input_tensor_by_name(request, \"PRESSURE\").as_numpy()\n temp_hum = pb_utils.get_input_tensor_by_name(request, \"TEMP_HUM\").as_numpy()\n temp_press = pb_utils.get_input_tensor_by_name(request, \"TEMP_PRESS\").as_numpy()\n\n out_0 = np.array([acc_y, acc_x, acc_z, pressure, temp_press, temp_hum, humidity, gyro_x, gyro_y, gyro_z]).transpose()\n\n # ACC_Y ACC_X ACC_Z PRESSURE TEMP_PRESS TEMP_HUM HUMIDITY GYRO_X GYRO_Y GYRO_Z\n min = np.array([-0.132551, -0.049693, 0.759847, 976.001709, 38.724998, 40.220890, 13.003981, -1.937896, -0.265019, -0.250647])\n max = np.array([ 0.093099, 0.150289, 1.177543, 1007.996338, 46.093750, 48.355824, 23.506138, 1.923712, 0.219204, 0.671759])\n\n # MinMax scaling\n out_0_scaled = (out_0 - min)/(max - min)\n\n # Create output tensor\n out_tensor_0 = pb_utils.Tensor(\"INPUT0\",\n out_0_scaled.astype(output0_dtype))\n\n inference_response = pb_utils.InferenceResponse(\n output_tensors=[out_tensor_0])\n responses.append(inference_response)\n\n return responses\n
Here there are two important things to note:
min
and max
arrays we found in the Data Processing section but we could have serialized the MinMaxScaler
using pickle
instead.As discussed in the \"Data processing\" section, to perform the anomaly detection step we need to compute the Mean Squared Error between the recontructed data and the actual input data. Due to this the configuration of the Postprocessor model will be somewhat more complicated than before: in addition to the output of the Autoencoder model we will need the output of the Preprocessor model.
To perform all of this we'll use the Python backend again.
As described in the previous section we will need to provide the following folder structure:
postprocessor\n\u251c\u2500\u2500 1\n\u2502 \u2514\u2500\u2500 model.py\n\u2514\u2500\u2500 config.pbtxt\n
"},{"location":"tutorials/AD-EdgeAI/#postprocessor-configuration","title":"Postprocessor Configuration\u00b6","text":"name: \"postprocessor\"\nbackend: \"python\"\n\ninput [\n {\n name: \"RECONSTR0\"\n data_type: TYPE_FP32\n dims: [ 1, 10 ]\n }\n]\ninput [\n {\n name: \"ORIG0\"\n data_type: TYPE_FP32\n dims: [ 1, 10 ]\n }\n]\noutput [\n {\n name: \"ANOMALY_SCORE0\"\n data_type: TYPE_FP32\n dims: [ 1 ]\n }\n]\noutput [\n {\n name: \"ANOMALY0\"\n data_type: TYPE_BOOL\n dims: [ 1 ]\n }\n]\ninstance_group [{ kind: KIND_CPU }]\n
As we can see we have two inputs and two outputs:
Let's see how this is computed by the Python model.
"},{"location":"tutorials/AD-EdgeAI/#postprocessor-model","title":"Postprocessor Model\u00b6","text":"import numpy as np\nimport json\n\nimport triton_python_backend_utils as pb_utils\n\ndef z_score(mse):\n return (mse - MEAN_MSE)/STD_MSE\n\n\nclass TritonPythonModel:\n\n def initialize(self, args):\n self.model_config = model_config = json.loads(args['model_config'])\n\n output0_config = pb_utils.get_output_config_by_name(\n model_config, \"ANOMALY_SCORE0\")\n output1_config = pb_utils.get_output_config_by_name(\n model_config, \"ANOMALY0\")\n\n self.output0_dtype = pb_utils.triton_string_to_numpy(\n output0_config['data_type'])\n self.output1_dtype = pb_utils.triton_string_to_numpy(\n output1_config['data_type'])\n\n def execute(self, requests):\n output0_dtype = self.output0_dtype\n output1_dtype = self.output1_dtype\n\n responses = []\n\n for request in requests:\n # Get input\n x_recon = pb_utils.get_input_tensor_by_name(request, \"RECONSTR0\").as_numpy()\n x_orig = pb_utils.get_input_tensor_by_name(request, \"ORIG0\").as_numpy()\n\n # Get Mean square error between reconstructed input and original input\n reconstruction_score = np.mean((x_orig - x_recon)**2, axis=1)\n \n #\u00a0Z-Score of Mean square error must be inside [-2; 2]\n anomaly = np.array([z_score(reconstruction_score) < -2.0 or z_score(reconstruction_score) > 2.0])\n\n # Create output tensors\n out_tensor_0 = pb_utils.Tensor(\"ANOMALY_SCORE0\",\n reconstruction_score.astype(output0_dtype))\n out_tensor_1 = pb_utils.Tensor(\"ANOMALY0\",\n anomaly.astype(output1_dtype))\n\n inference_response = pb_utils.InferenceResponse(\n output_tensors=[out_tensor_0, out_tensor_1])\n responses.append(inference_response)\n\n return responses\n
As you can see the script is simple:
Note: MEAN_MSE
and STD_MSE
are the mean value and the standard deviation of the Mean Squared Error computed on the test set and correspond to the reconstruction_scores_pd.mean()
and reconstruction_scores_pd.std()
we used in the previous section. We didn't set them as they change for every training performed on the Autoencoder. Be sure to set it to their proper values before trying this model on the Triton server!
To make things easier for ourselves and improve performance we'll consolidate the AI pipeline into an Ensemble Model.
We will need to provide the following folder structure:
ensemble_pipeline\n\u251c\u2500\u2500 1\n\u2514\u2500\u2500 config.pbtxt\n
Note that the 1
folder is empty. The ensemble model essentially describe how to connect the models that belong to the processing pipeline.
Therefore we'll need to focus on the configuration only.
name: \"ensemble_pipeline\"\nplatform: \"ensemble\"\nmax_batch_size: 0\ninput [\n {\n name: \"ACC_X\"\n data_type: TYPE_FP32\n dims: [ 1 ]\n }\n]\ninput [\n {\n name: \"ACC_Y\"\n data_type: TYPE_FP32\n dims: [ 1 ]\n }\n]\n ...\ninput [\n {\n name: \"TEMP_PRESS\"\n data_type: TYPE_FP32\n dims: [ 1 ]\n }\n]\noutput [\n {\n name: \"ANOMALY_SCORE0\"\n data_type: TYPE_FP32\n dims: [ 1 ]\n }\n]\noutput [\n {\n name: \"ANOMALY0\"\n data_type: TYPE_BOOL\n dims: [ 1 ]\n }\n]\nensemble_scheduling {\n step [\n {\n model_name: \"preprocessor\"\n model_version: -1\n input_map{\n key: \"ACC_X\"\n value: \"ACC_X\"\n }\n input_map{\n key: \"ACC_Y\"\n value: \"ACC_Y\"\n }\n ...\n input_map{\n key: \"TEMP_PRESS\"\n value: \"TEMP_PRESS\"\n }\n output_map {\n key: \"INPUT0\"\n value: \"preprocess_out\"\n }\n },\n {\n model_name: \"tf_autoencoder_fp32\"\n model_version: -1\n input_map {\n key: \"INPUT0\"\n value: \"preprocess_out\"\n }\n output_map {\n key: \"OUTPUT0\"\n value: \"autoencoder_output\"\n }\n },\n {\n model_name: \"postprocessor\"\n model_version: -1\n input_map {\n key: \"RECONSTR0\"\n value: \"autoencoder_output\"\n }\n input_map {\n key: \"ORIG0\"\n value: \"preprocess_out\"\n }\n output_map {\n key: \"ANOMALY_SCORE0\"\n value: \"ANOMALY_SCORE0\"\n }\n output_map {\n key: \"ANOMALY0\"\n value: \"ANOMALY0\"\n }\n }\n ]\n}\n
The configuration is split in two main parts:
To better visualize the configuration we can look at the graph below.
"},{"location":"tutorials/AD-EdgeAI/#conversion-results","title":"Conversion results\u00b6","text":"At this point we should have a folder structure that looks like this:
models\n\u251c\u2500\u2500 ensemble_pipeline\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 1\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 config.pbtxt\n\u251c\u2500\u2500 postprocessor\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 1\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 model.py\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 config.pbtxt\n\u251c\u2500\u2500 preprocessor\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 1\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 model.py\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 config.pbtxt\n\u2514\u2500\u2500 tf_autoencoder_fp32\n \u251c\u2500\u2500 1\n \u2502\u00a0\u00a0 \u2514\u2500\u2500 model.savedmodel\n \u2502\u00a0\u00a0 \u251c\u2500\u2500 assets\n \u2502\u00a0\u00a0 \u251c\u2500\u2500 keras_metadata.pb\n \u2502\u00a0\u00a0 \u251c\u2500\u2500 saved_model.pb\n \u2502\u00a0\u00a0 \u2514\u2500\u2500 variables\n \u2502\u00a0\u00a0 \u251c\u2500\u2500 variables.data-00000-of-00001\n \u2502\u00a0\u00a0 \u2514\u2500\u2500 variables.index\n \u2514\u2500\u2500 config.pbtxt\n
"},{"location":"tutorials/AD-EdgeAI/#kura-deployment","title":"Kura Deployment\u00b6","text":"We can now move our pipeline to the target device for inference on the edge.
We want to perform anomaly detection in real time, directly within the edge device, using the same data we used to collect for our training.
"},{"location":"tutorials/AD-EdgeAI/#triton-component-configuration","title":"Triton component configuration\u00b6","text":"To do so we need to copy the models
folder on the target device. For this example we'll use the /home/pi/models
path.
We can now move to the Kura web UI and create a new Triton Server Container Service component instance. The complete documentation can be found here.
In this example we'll call it TritonContainerService
.
Then we'll need to configure it to run our models. Move to the TritonContainerService
configuration interface and set the following parameters:
nvcr.io/nvidia/tritonserver:22.07-tf2-python-py3
in this example./home/pi/models
preprocessor,postprocessor,tf_autoencoder_fp32,ensemble_pipeline
tensorflow,version=2
since Tensorflow 2 is the only available Tensorflow backend in the Triton container image we're using.You can leave everything else as default.
Once you press the \"Apply\" button Kura will create a new container from the Triton image we set and spin up the service with our models loaded.
pi@raspberrypi:~ $ docker ps\nCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES\n4deae2857b6f nvcr.io/nvidia/tritonserver:22.07-tf2-python-py3 \"tritonserver --mode\u2026\" 13 seconds ago Up 11 seconds 0.0.0.0:4000->8000/tcp, :::4000->8000/tcp, 0.0.0.0:4001->8001/tcp, :::4001->8001/tcp, 0.0.0.0:4002->8002/tcp, :::4002->8002/tcp tritonserver-kura\n
Note: if no container is created check that the \"Container Orchestration Service\" is enabled in the Kura UI. Full documentation for the service can be found here.
Note: if you see an error in the logs like \"Internal: Unable to initialize shared memory key 'triton_python_backend_shm_region_2' to requested size (67108864 bytes). If you are running Triton inside docker, use '--shm-size' flag to control the shared memory region size. Each Python backend model instance requires at least 64MBs of shared memory.\", you can update the default shared memory size allocated by the Docker daemon. Go to /etc/docker/daemon.json
, set \"default-shm-size\": \"200m\"
and restart the Docker daemon with: sudo systemctl restart docker
.
Finally we can move to the \"Wire Graph\" UI and create the AI component (in the Emitters/Receiver menu) for interfacing with the Triton instance we just created. We'll call it Triton
in this example.
We just need to change two parameter in the configuration:
TritonContainerService
we created at the step aboveThe resulting wire graph is the following:
And that's it! We should now see the anomaly detection results coming to Kapua in addition to the SenseHat data.
"},{"location":"tutorials/AD-EdgeAI/#complete-example","title":"Complete Example\u00b6","text":"A similar but more complete example of the feature presented in this notebook is available in the official Kura\u2122 repository containing all the code and the configuration needed to make it work.
Give it a try!
"}]} \ No newline at end of file diff --git a/docs-release-5.6/sitemap.xml.gz b/docs-release-5.6/sitemap.xml.gz index d7a1861d381316d209493aedb4ffb4266d459d84..3072fe73fff1319549847951c9efc11d6fce5c39 100644 GIT binary patch delta 13 Ucmb=gXP58h;HdObp2%JS02*lnxBvhE delta 13 Ucmb=gXP58h;9&Qan#f)O02iJEJ^%m!