From 3b1e16f436fee3a647b04e237a454cff79cea92b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 14 Oct 2024 13:32:20 +0000 Subject: [PATCH] Deployed 80a72ea83 to docs-develop with MkDocs 1.5.3 and mike 1.1.2 --- .../asset-implemetation/index.html | 12 +++++------- docs-develop/search/search_index.json | 2 +- docs-develop/sitemap.xml.gz | Bin 127 -> 127 bytes 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/docs-develop/connect-field-devices/asset-implemetation/index.html b/docs-develop/connect-field-devices/asset-implemetation/index.html index cb580741df..abdd89f1ad 100644 --- a/docs-develop/connect-field-devices/asset-implemetation/index.html +++ b/docs-develop/connect-field-devices/asset-implemetation/index.html @@ -4618,17 +4618,15 @@

Channel Definition

  • enabled: each channel can be separately enabled using this flag.
  • name: unique user-friendly name for a channel
  • type: represents the type of operation supported. Possible values are: READ, WRITE, READ/WRITE
  • -
  • -

    value.type: represents the data type that will be used when creating the Wire Envelope for the connected components.

    -
  • -
  • -

    scale: an optional scaling factor to be applied only to the numeric values retrieved from the field. It is parsed as a double. See below for more details.

    -
  • +
  • value.type: represents the data type that will be used when creating the Wire Envelope for the connected components and the output value for READ channel.
  • +
  • scale: an optional scaling factor to be applied only to the numeric values retrieved from the field. It is parsed as a double. See below for more details.
  • offset: an optional offset value that will be added only to the numeric values retrieved from the field. It is parsed as a double. See below for more details.
  • scaleoffset.type: Allows to customise the way scale and offset is applied. See below for more details.
  • unit: an optional string value that will be added to the asset channel read to represent the unit of measure associated to that specific channel.
  • listen: if supported by the associated driver, allows to receive notifications by the driver on events. This flag currently has effect only inside Kura Wires.
  • +

    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.

    Arithmetic with scale and offset

    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.

    @@ -4646,7 +4644,7 @@

    Arithmetic with scale and offset

    The values of the scale and offset parameters are parsed from channel configuration as doubles.

    The mode can be selected in the following way:

    Example of DOUBLE mode: diff --git a/docs-develop/search/search_index.json b/docs-develop/search/search_index.json index 7991f2e8d3..00b6c5c1cc 100644 --- a/docs-develop/search/search_index.json +++ b/docs-develop/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":"

    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:

    "},{"location":"administration/application-management/","title":"Application Management","text":""},{"location":"administration/application-management/#package-installation","title":"Package Installation","text":"

    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:

    Directory Description 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:

    /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:

    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 ServiceTrackers 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.

    1. 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.

    2. 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:

    3. 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.

    4. 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
    5. 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.

    6. 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
    7. 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.

    "},{"location":"cloud-api/built-in-cloud/","title":"Built-in Cloud Services","text":"

    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.

    "},{"location":"cloud-api/built-in-cloud/#cloudservice","title":"CloudService","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 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:

    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:

    The default CloudService implementations publishes the following lifecycle messages:

    1. BIRTH message: sent immediately when device is connected to the cloud platform. The BIRTH message is published with priority 0 and QoS 1;
    2. DISCONNECT message: sent immediately before device is disconnected from the cloud platform. The DISCONNECT message is published with priority 0 and QoS 0;
    3. delayed BIRTH message: sent when new cloud application handler becomes available, a DP is installed or removed, GPS position is locked (can be disabled), or when modem status changes (can be disabled). These messages are cached for 30 seconds before sending. If no other message of such type arrives the message is sent; otherwise the BIRTH is cached and the timeout restarts. This is to avoid sending multiple messages when the framework starts. The message is published with priority 0 and QoS 1;
    "},{"location":"cloud-api/built-in-cloud/#mqttdatatransport","title":"MqttDataTransport","text":"

    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:

    "},{"location":"cloud-api/cloud-conn-dev-guide/","title":"Cloud connection developer guide","text":"

    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.

    "},{"location":"cloud-api/cloud-conn-dev-guide/#implement-the-cloudconnectionfactory-interface","title":"Implement the CloudConnectionFactory interface","text":"

    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:

    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:

    "},{"location":"cloud-api/overview/#concepts","title":"Concepts","text":"

    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:

    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 KuraMessages. 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.

    "},{"location":"cloud-api/overview/#publishers-and-subscribers","title":"Publishers and Subscribers","text":"

    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.

    "},{"location":"cloud-api/overview/#cloudsubscriber","title":"CloudSubscriber","text":"

    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.

    "},{"location":"cloud-api/overview/#command-and-control","title":"Command and control","text":"

    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:

    Response parameters:

    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.pids of the ConfigurableComponents 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.

    "},{"location":"cloud-api/overview/#backwards-compatibility","title":"Backwards compatibility","text":"

    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.

    "},{"location":"cloud-api/user-guide/","title":"User guide","text":"

    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

    1. Instantiation and configuration of the Cloud Connection.
    2. Instantiation and configuration of a Publisher.
    3. Binding an application to the Publisher.
    "},{"location":"cloud-api/user-guide/#creating-a-new-cloud-connection","title":"Creating a new Cloud Connection","text":"
    1. Open the Cloud Connections section of the Web UI:

    2. Create a new Cloud Connection

      1. Click on the New Connection button

      2. 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.

      3. 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
      4. Configure the DataService-KAPUA service.

        In order to enable automatic connection, set the Connect Auto-on-startup parameter to true

    "},{"location":"cloud-api/user-guide/#creating-and-configuring-a-new-publisher","title":"Creating and configuring a new Publisher","text":"
    1. Select to the connection to be used from the list.

    2. Click on the New Pub/Sub button.

    3. 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.

    4. Enter an unique kura.service.pid identifier in the New Publisher/Subscriber PID field.

    5. Click Apply, you should see the publisher configuration

    6. Select and configure the newly created publisher instance, and then click Apply

    "},{"location":"cloud-api/user-guide/#binding-an-application-to-a-publisher","title":"Binding an application to a publisher","text":"
    1. Select the application instance configuration

    2. Find the configuration entry that represents a Publisher reference.

    3. Click on the Select available targets link and select the desired Publisher instance to bind to.

    4. Click on Apply

    "},{"location":"cloud-platform/kura-aws-cloud/","title":"Amazon AWS IoT\u2122 platform","text":""},{"location":"cloud-platform/kura-aws-cloud/#overview","title":"Overview","text":"

    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":""},{"location":"cloud-platform/kura-aws-cloud/#device-registration","title":"Device registration","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:

    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.

    "},{"location":"cloud-platform/kura-aws-cloud/#4-create-a-new-certificate-for-the-device","title":"4. Create a new certificate for the device.","text":"

    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.

    "},{"location":"cloud-platform/kura-aws-cloud/#8-configure-the-ssl-parameters-using-the-kura-web-ui","title":"8. Configure the SSL parameters using the Kura Web UI.","text":"
    1. 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.

    2. 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.

    3. 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.

    4. Paste the contents of the obtained outKey.pem in the \"Private Key\" field.

    5. Paste the contents of xxxxxxxxxx-certificate.pem.crt in the Certificate field.

      You should see a screen like this

    6. Click the Apply button to confirm.

    7. 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.

    "},{"location":"cloud-platform/kura-aws-cloud/#9-setup-a-new-cloud-connection","title":"9. Setup a new cloud connection","text":"
    1. Click on Cloud Connections in the left panel, and setup a new cloud connection

    2. Click on the New Connection button at the top of the page and set the following parameters in the dialog:

      • Cloud Connection Factory PID -> org.eclipse.kura.cloud.CloudService
      • Cloud Connection Service PID -> org.eclipse.kura.cloud.CloudService-AWS

      Press the Create button to confirm and then select the newly created CloudService instance from the list.

    3. 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
    4. Clear the value of the username and password fields.

    5. 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).

    6. 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.

    7. 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).

    8. Press the Apply button in the top left section to commit the changes to the MqttDataTransport-AWS.

    9. Enter a name without the $ character for the topic.control-prefix setting in the CloudService-AWS tab, for example aws-control.

    10. 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:

      • republish.mqtt.birth.cert.on.gps.lock -> false
      • republish.mqtt.birth.cert.on.modem.detect -> false
      • enable.default.subscriptions -> false
    11. Click the Apply button to save the changes.

    "},{"location":"cloud-platform/kura-aws-cloud/#10-connect-to-the-cloud-platform","title":"10. Connect to the cloud platform","text":"

    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:

    Now review and update the configuration of each Kura Cloud stack component as outline below.

    "},{"location":"cloud-platform/kura-azure/#mqttdatatransport","title":"MqttDataTransport","text":"

    Modify the service configuration parameters as follows:

    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 .

    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.

    This configuration allows the publication on the default messages/events endpoint on the IoT Hub\u2122.

    "},{"location":"cloud-platform/kura-ec-cloud/","title":"Eurotech Everyware Cloud\u2122 platform","text":"

    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.

    "},{"location":"cloud-platform/kura-ec-cloud/#cloudservice","title":"CloudService","text":"

    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.

    "},{"location":"cloud-platform/kura-ec-cloud/#mqttdatatransport","title":"MqttDataTransport","text":"

    While the majority of default settings in the MqttDataTransport can be left unchanged, the following parameters must be modified:

    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.

    "},{"location":"cloud-platform/kura-hono/#cloudservice","title":"CloudService","text":"

    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.

    "},{"location":"cloud-platform/kura-hono/#mqttdatatransport","title":"MqttDataTransport","text":"

    While the majority of default settings in the MqttDataTransport can be left unchanged, the following parameters must be modified:

    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.

    "},{"location":"cloud-platform/kura-kapua/#cloudservice","title":"CloudService","text":"

    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.

    "},{"location":"cloud-platform/kura-kapua/#mqttdatatransport","title":"MqttDataTransport","text":"

    While the majority of default settings in the MqttDataTransport can be left unchanged, the following parameters must be modified:

    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:

    1. Define a common MQTT topic namespace.
    2. Define a common MQTT state management.
    3. Define a common MQTT payload.

    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:

    1. PubSub Protocol: this is the main topology upon which the architecture is developed.
    2. Report by Exception (RBE): messages need to be sent by the Edge Node only when values at the edge change, and the message should contain only the value/metrics that changed. There is no need for continuos polling; although it is higly discouraged, it is not mandatory to have Edge Nodes apply the RBE.
    3. Continuos Session Awareness: Host Applications are aware of the state of the Edge Nodes, and Edge Nodes are aware of the state of the Host Applications. This continuos session awareness is achieved by the means of birth and death certificates and state messages (continue the reading to find out more) and is the key to allow reporting by exception.
    4. Birth and Death certificates: these messages represent the state of Edge Nodes and Devices (online/offline + data that will be reported). The birth messages are always the first ones that are sent from the Edge Node, and the delivery of death certificates is ensured through the MQTT Will message, even if the connection is lost ungracefully. The birth messages always contain all the metrics that the Device or Edge Node will ever report on. If a new metric is added or a metric gets removed, then a new session needs to be estabilished.
    5. 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.

    "},{"location":"cloud-platform/kura-sparkplug/#eclipse-sparkplug-topic-namespace","title":"Eclipse Sparkplug Topic Namespace","text":"

    All clients using the specification must adhere to the following topic namespace:

    namespace/group_id/message_type/edge_node_id/[device_id]\n

    where:

    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.

    "},{"location":"cloud-platform/kura-sparkplug/#operational-behavior","title":"Operational Behavior","text":"

    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":""},{"location":"cloud-platform/kura-sparkplug/#cloud-connection-configuration","title":"Cloud Connection Configuration","text":""},{"location":"cloud-platform/kura-sparkplug/#cloud-endpoint-layer-configuration","title":"Cloud Endpoint Layer Configuration","text":"

    The cloud endpoint layer allows to attach CloudPublishers and CloudSubscribers to publish/subscribe messages on Sparkplug topics.

    "},{"location":"cloud-platform/kura-sparkplug/#sparkplug-device","title":"Sparkplug Device","text":"

    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):

    "},{"location":"cloud-platform/kura-sparkplug/#sparkplug-device-payload","title":"Sparkplug Device Payload","text":"

    The payload of DDATA message will be encoded using the Sparkplug B Protobuf definition converting the KuraPayload into Sparkplug payload as follows:

    "},{"location":"cloud-platform/kura-sparkplug/#sparkplug-subscriber","title":"Sparkplug Subscriber","text":"

    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 KuraMessages containing a KuraPayload such that:

    "},{"location":"cloud-platform/kura-sparkplug/#data-service-layer-configuration","title":"Data Service Layer Configuration","text":"

    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.

    "},{"location":"cloud-platform/kura-sparkplug/#data-transport-layer-configuration","title":"Data Transport Layer Configuration","text":"

    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.

    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.

    "},{"location":"cloud-platform/kura-sparkplug/#sparkplug-implementation-details","title":"Sparkplug Implementation Details","text":""},{"location":"cloud-platform/kura-sparkplug/#edge-node","title":"Edge Node","text":""},{"location":"cloud-platform/apache-camel-integration/kura-camel-app/","title":"Apache Camel\u2122 as a Kura application","text":"

    As of 2.1.0 Kura provides a set of different ways to implement an application backed by Camel:

    "},{"location":"cloud-platform/apache-camel-integration/kura-camel-app/#kura-cloud-endpoint","title":"Kura cloud endpoint","text":"

    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 Description applicationId 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 Description CamelKuraCloudService.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

    "},{"location":"cloud-platform/apache-camel-integration/kura-camel-app/#selecting-a-cloud-service","title":"Selecting a cloud service","text":"

    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

    "},{"location":"cloud-platform/apache-camel-integration/kura-camel-app/#custom-camel-routers","title":"Custom Camel routers","text":"

    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.

    "},{"location":"cloud-platform/apache-camel-integration/kura-camel-app/#camel-components","title":"Camel components","text":"

    The base classes in org.eclipse.kura.camel.component are intended to help creating new OSGi DS components base on Camel.

    "},{"location":"cloud-platform/apache-camel-integration/kura-camel-app/#xml-based-component","title":"XML based component","text":"

    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.

    "},{"location":"cloud-platform/apache-camel-integration/kura-camel-app/#java-dsl-based-component","title":"Java DSL based component","text":"

    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.

    "},{"location":"cloud-platform/apache-camel-integration/kura-camel-app/#kura-camel-quickstart","title":"Kura Camel quickstart","text":"

    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.

    "},{"location":"cloud-platform/apache-camel-integration/kura-camel-app/#kura-camel-aggregation","title":"Kura Camel aggregation","text":"

    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.

    "},{"location":"cloud-platform/apache-camel-integration/kura-camel-cloud/","title":"Apache Camel\u2122 as a Kura cloud service","text":"

    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:

    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.

    "},{"location":"connect-field-devices/asset-implemetation/","title":"Asset implementation","text":"

    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 3084

    The 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":""},{"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:

    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:

    Example of DOUBLE mode: channel configured with:

    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:

    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:

    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":""},{"location":"connect-field-devices/asset-implemetation/#channels-download","title":"Channels download","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.

    "},{"location":"connect-field-devices/asset-implemetation/#force-import-empty-string-policy","title":"Force import empty string policy","text":"

    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.

    "},{"location":"connect-field-devices/asset-v1-mqtt-namespace/","title":"ASSET-V1 MQTT Namespace","text":"

    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:

    "},{"location":"connect-field-devices/asset-v1-mqtt-namespace/#execread","title":"EXEC/read","text":"

    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:

    "},{"location":"connect-field-devices/asset-v1-mqtt-namespace/#response-format_1","title":"Response Format","text":"

    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:

    "},{"location":"connect-field-devices/asset-v1-mqtt-namespace/#execwrite","title":"EXEC/write","text":"

    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:

    "},{"location":"connect-field-devices/asset-v1-mqtt-namespace/#response-format_2","title":"Response format","text":"

    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.

    "},{"location":"connect-field-devices/driver-and-assets/","title":"Drivers, Assets and Channels","text":"

    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 3084

    The 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. 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.

    "},{"location":"connect-field-devices/eddystone-driver/#channel-configuration","title":"Channel configuration","text":"

    The Eddystone Driver channel can be configured with the following parameters:

    "},{"location":"connect-field-devices/field-protocols/","title":"Field Protocols","text":"

    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:

    "},{"location":"connect-field-devices/gpio-driver/#installation","title":"Installation","text":"

    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.

    "},{"location":"connect-field-devices/gpio-driver/#channel-configuration","title":"Channel configuration","text":"

    The GPIO Driver channel can be configured with the following parameters:

    "},{"location":"connect-field-devices/gpio-driver/#drive-a-led-using-the-gpio-driver","title":"Drive a LED using the GPIO Driver","text":"

    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. 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.

    "},{"location":"connect-field-devices/ibeacon-driver/#channel-configuration","title":"Channel configuration","text":"

    The iBeacon Driver channel can be configured with the following parameters:

    "},{"location":"connect-field-devices/opcua-driver/","title":"OPC UA Driver","text":"

    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:

    "},{"location":"connect-field-devices/opcua-driver/#instance-creation","title":"Instance creation","text":"

    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.

    "},{"location":"connect-field-devices/opcua-driver/#channel-configuration","title":"Channel configuration","text":"

    The OPC UA Driver channel configuration is composed of the following parameters:

    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:

    1. Download the certificate used by the server, usually this can be done from server management UI.
    2. Copy the downloaded certificate to the gateway using SSH.
    3. 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
    4. Update the following parameters in driver configuration:

    5. Keystore Path : Set the absolute path of the opcua-keystore.ks file created at step 3.
    6. **Security Policy ** -> Set the desired option
    7. Client Certificate Alias -> Set the value of the CLIENT_ALIAS script variable (the default is client-cert)
    8. Enable Server Authentication -> true
    9. Keystore type -> JKS
    10. Keystore Password -> Set the value of the KEYSTORE_PASSWORD script variable (the default value is changeit)
    11. Application URI -> Set the value of the APPLICATION_ID script variable (default value should be already ok).

    12. 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:

    13. Make a connection attempt using OPC-UA driver, this will likely fail because the server does not trust client certificate.
    14. After the failed connection attempt, the server should display the certificate used by the driver in the administration UI. The server UI should allow to set it as trusted.
    15. Make another connection attempt once the certificate has been set to trusted, this connection attempt should succeed.
    "},{"location":"connect-field-devices/opcua-driver/#substree-subscription","title":"Substree Subscription","text":"

    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:

    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.

    "},{"location":"connect-field-devices/s7-driver/","title":"S7comm Driver","text":"

    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:

    "},{"location":"connect-field-devices/s7-driver/#instance-creation","title":"Instance creation","text":"

    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.

    "},{"location":"connect-field-devices/s7-driver/#channel-configuration","title":"Channel configuration","text":"

    The S7 Driver channel configuration is composed of the following parameters:

    "},{"location":"connect-field-devices/s7-driver/#data-types","title":"Data Types","text":"

    When performing operations that deal with numeric data, two data types are involved:

    1. 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.

    2. 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 Sign INT 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:

    "},{"location":"connect-field-devices/s7-driver/#array-data","title":"Array Data","text":"

    The driver supports transferring data as raw byte arrays or ASCII strings:

    "},{"location":"connect-field-devices/s7-driver/#writing-single-bits","title":"Writing Single Bits","text":"

    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.

    "},{"location":"connect-field-devices/sensehat-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.

    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 sensor

    The 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:

    "},{"location":"connect-field-devices/sensehat-driver/#coordinates","title":"Coordinates","text":"

    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.

    "},{"location":"connect-field-devices/sensehat-driver/#monochrome-framebuffer","title":"Monochrome framebuffer","text":"

    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:

    "},{"location":"connect-field-devices/sensehat-driver/#rgb565-framebuffer","title":"RGB565 framebuffer","text":"

    The following resource allows writing the framebuffer using the RGB565 format:

    "},{"location":"connect-field-devices/sensehat-driver/#mode-independent-resources","title":"Mode independent resources","text":"

    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":"
    1. Open the Wires section of the Kura Web UI.
    2. Create an Asset that emits joystick events like the one described in the Joystick section. Only left_release, right_release, up_release and down_release channels will be used. Make sure to enable the listen flag for the channels.
    3. Create the Asset described in the LED Matrix section.
    4. Create a Script Filter and paste the code below in the script field.
    5. Connect the Joystick Asset to the input port of the Script Filter, and the output port of the Script filter to the framebuffer Asset.
    6. Open the Drivers and Assets section of the Kura Web UI, select the framebuffer Asset, click on the Data tab and select front and back colors. For example for using green as front color and red as back color, write 1 as Value for the front_g and back_r channels.
    7. You should now be able to move the green pixel with the joystick.
    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":"
    1. Open the Wires section of the Kura Web UI.
    2. Create the Asset described in the LED Matrix section.
    3. Create a Script Filter and paste the code below in the script field.
    4. Create a Timer that ticks every 16 milliseconds.
    5. Connect the Timer to the input port of the Script Filter, and the output port of the Script filter to the framebuffer Asset.
    6. The framebuffer should now display an animation, the animation can be changed by modifying the wave parameters and setting script.context.drop to false.
    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. 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.

    "},{"location":"connect-field-devices/sensortag-driver/#channel-configuration","title":"Channel configuration","text":"

    The SensorTag Driver channel can be configured with the following parameters:

    "},{"location":"connect-field-devices/xdk-driver/","title":"Xdk Driver","text":"

    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):

    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* 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_Z number 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).

    "},{"location":"connect-field-devices/xdk-driver/#channel-configuration","title":"Channel configuration","text":"

    The Xdk Driver channel can be configured with the following parameters:

    "},{"location":"core-services/active-mq-artemis-broker/","title":"ActiveMQ Artemis MQTT Broker","text":"

    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.

    "},{"location":"core-services/clock-service/","title":"Clock Service","text":"

    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:

    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.

    "},{"location":"core-services/clock-service/#simple-configuration-example","title":"Simple configuration example","text":"
    # 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:

    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:

    "},{"location":"core-services/container-orchestration-image-auth/","title":"Eclipse Eclipse Kura Container Image Authenticity and Allowlist Enforcement feature","text":"

    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:

    "},{"location":"core-services/container-orchestration-image-auth/#unmanaged-containers","title":"Unmanaged containers","text":"

    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).

    "},{"location":"core-services/container-orchestration-image-auth/#startup-of-the-enforcement-feature","title":"Startup of the Enforcement Feature","text":"

    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.

    "},{"location":"core-services/container-orchestration-image-auth/#managed-containers","title":"Managed containers","text":"

    As explained in the previous section, Managed Containers (i.e. org.eclipse.kura.container.provider.ContainerInstances) 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.

    "},{"location":"core-services/container-orchestration-image-auth/#example-scenarios_1","title":"Example Scenarios","text":""},{"location":"core-services/container-orchestration-image-auth/#container-instance-digest","title":"Container Instance Digest","text":"

    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.

    1. That you have already configured the Container Orchestrator and have a container instance already created. Please see the usage doc, to learn the basics of the orchestrator.
    2. That the image you are trying to pull supports the architecture of the gateway.
    "},{"location":"core-services/container-orchestration-provider-authenticated-registries/#private-docker-hub-registries","title":"Private Docker-Hub Registries","text":""},{"location":"core-services/container-orchestration-provider-authenticated-registries/#preparation","title":"Preparation:","text":""},{"location":"core-services/container-orchestration-provider-authenticated-registries/#procedure","title":"Procedure:","text":"
    1. Populate the image name field. The username containing the private image must be placed before the image name separated by a forward slash. This is demonstrated below:
    2. **Image Name: ** <Docker-Hub username>/<image name> for exampleeclipse/kura.

    3. Populate the credential fields:

    4. Authentication Registry URL: This field should be left blank.
    5. Authentication Username: Your Docker Hub username.
    6. Password: Your Docker Hub password.

    "},{"location":"core-services/container-orchestration-provider-authenticated-registries/#amazon-web-services-elastic-container-registries-aws-ecr","title":"Amazon Web Services - Elastic Container Registries (AWS-ECR)","text":""},{"location":"core-services/container-orchestration-provider-authenticated-registries/#preparation_1","title":"Preparation:","text":""},{"location":"core-services/container-orchestration-provider-authenticated-registries/#procedure_1","title":"Procedure:","text":"
    1. 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>.

    2. 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.

    3. Populating information on the gateway.

    4. **Image Name: ** enter the full URI without the tag.<identifier>.dkr.ecr.<ecr-region>.amazonaws.com/<directory>/<image name>
    5. Image Tag: enter only the image tag found at the end of the URI <image tag>
    6. Authentication Registry URL: Paste only the part of the URI before the image name <identifier>.dkr.ecr.<ecr-region>.amazonaws.com/<directory>/
    7. Authentication Username: will be AWS
    8. Password: will be the string created in step two.

    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:

    "},{"location":"core-services/container-orchestration-provider-usage/#creating-your-first-container","title":"Creating your first container.","text":"

    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:

    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.

    "},{"location":"core-services/container-orchestration-provider/","title":"Container Orchestration Provider","text":"

    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:

    "},{"location":"core-services/device-configuration-changes/","title":"Device Configuration Changes","text":"

    Kura can detect changes to the components and publish them using a selected Cloud Publisher. There are two main components that enable this:

    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.

    "},{"location":"core-services/device-configuration-changes/#configuration-change-manager","title":"Configuration Change Manager","text":"

    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:

    "},{"location":"core-services/h2db-service/#supported-features","title":"Supported Features","text":"

    Kura supports the following H2 database features:

    By default, the DataService in Kura uses the H2 database to persist the messages.

    "},{"location":"core-services/h2db-service/#limitations","title":"Limitations","text":"

    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.

    "},{"location":"core-services/h2db-service/#usage","title":"Usage","text":""},{"location":"core-services/h2db-service/#creating-a-new-h2-database-instance","title":"Creating a new H2 database instance","text":"

    To create a new H2 database instance, use the following procedure:

    1. Open the Administrative UI and press the + button in the side menu, under the Services section. A pop-up dialog should appear.
    2. Select org.eclipse.kura.core.db.H2DbService from the Factory drop-down list, enter an arbitrary name for the new instance and click Apply.
    3. An entry for the newly created instance should appear in the side menu under Services, click on it to review its configuration. It is not possible to create different DB instances that manage the same DB URL. When creating a new instance please make sure that the URL specified in the field db.connector.url is not managed by another instance.
    "},{"location":"core-services/h2db-service/#configuration-parameters","title":"Configuration Parameters","text":"

    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.

    "},{"location":"core-services/h2db-service/#selecting-a-database-instance-for-existing-components","title":"Selecting a database instance for existing components","text":"

    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:

    1. Open the Web UI and press the + button in the side menu, under the Services section. A pop-up dialog should appear.
    2. Select org.eclipse.kura.core.db.H2DbServer from the Factory drop-down\u200b list, enter an arbitrary name for the new instance and click Apply.
    3. Clicking on the name of the new server instance on the left side of the Web UI\u200b. The configuration of the server component will appear.
    4. Set the db.server.type field to TCP.
    5. Review the server options under db.server.commandline, check the official documentation for more information about the available options.
    6. Set the db.server.enabled to true.

    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:

    1. Create a new H2DbServer instance.
    2. Set the db.server.type field to WEB.
    3. Enter appropriate parameters for the Web server in the db.server.commandline field. An example of valid settings can be: -webPort 9123 -webAllowOthers -ifExists -webExternalNames <device-ip>.
    4. Set the db.server.enabled to true.

    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:

    1. Open the configuration of the desired database instance in the Web UI.
    2. Enter the new password in the db.password field.
    3. Click Apply.

    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.

    "},{"location":"core-services/network-status-rest-v1/#request-definitions","title":"Request definitions","text":""},{"location":"core-services/network-status-rest-v1/#getinterfaceids","title":"GET/interfaceIds","text":""},{"location":"core-services/network-status-rest-v1/#getstatus","title":"GET/status","text":""},{"location":"core-services/network-status-rest-v1/#poststatusbyinterfaceid","title":"POST/status/byInterfaceId","text":""},{"location":"core-services/network-status-rest-v1/#json-definitions","title":"JSON definitions","text":""},{"location":"core-services/network-status-rest-v1/#interfaceids","title":"InterfaceIds","text":"

    An object containing a list of network interface identifiers

    Properties:

    {\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:

    {\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:

    {\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:

    {\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:

    {\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      \"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:

    "},{"location":"core-services/network-status-rest-v1/#ipaddressstring","title":"IPAddressString","text":"

    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:

    "},{"location":"core-services/network-status-rest-v1/#networkinterfaceipaddressstatus","title":"NetworkInterfaceIpAddressStatus","text":"

    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:

    "},{"location":"core-services/network-status-rest-v1/#wifichannel","title":"WifiChannel","text":"

    This class represent a WiFi channel, providing the channel number, frequency, status and other useful information.

    Properties:

    "},{"location":"core-services/network-status-rest-v1/#wifiaccesspoint","title":"WifiAccessPoint","text":"

    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:

    "},{"location":"core-services/network-status-rest-v1/#modemmodepair","title":"ModemModePair","text":"

    This object represents a pair of Modem Mode list and a preferred one.

    Properties:

    "},{"location":"core-services/network-status-rest-v1/#sim","title":"Sim","text":"

    This class contains all relevant properties to describe a SIM (Subscriber Identity Module).

    Properties:

    "},{"location":"core-services/network-status-rest-v1/#bearer","title":"Bearer","text":"

    This object describes the Bearer or Context associated to a modem connection.

    Properties:

    "},{"location":"core-services/network-status-rest-v1/#modemports","title":"ModemPorts","text":"

    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:

    "},{"location":"core-services/network-status-rest-v1/#networkinterfacetype","title":"NetworkInterfaceType","text":"

    The type of a network interface.

    "},{"location":"core-services/network-status-rest-v1/#networkinterfacestate","title":"NetworkInterfaceState","text":"

    The state of a network interface.

    "},{"location":"core-services/network-status-rest-v1/#wificapability","title":"WifiCapability","text":"

    The capability of a WiFi interface.

    "},{"location":"core-services/network-status-rest-v1/#wifimode","title":"WifiMode","text":"

    Modes of operation for wifi interfaces

    "},{"location":"core-services/network-status-rest-v1/#wifisecurity","title":"WifiSecurity","text":"

    Flags describing the security capabilities of an access point.

    "},{"location":"core-services/network-status-rest-v1/#modemporttype","title":"ModemPortType","text":"

    The type of a modem port.

    "},{"location":"core-services/network-status-rest-v1/#modemcapability","title":"ModemCapability","text":"

    The generic access technologies families supported by a modem.

    "},{"location":"core-services/network-status-rest-v1/#modemmode","title":"ModemMode","text":"

    The generic access mode a modem supports.

    "},{"location":"core-services/network-status-rest-v1/#modemband","title":"ModemBand","text":"

    The radio bands supported by a modem when connected to a mobile network.

    "},{"location":"core-services/network-status-rest-v1/#simtype","title":"SimType","text":"

    The SIM (Subscriber Identity Module) type.

    "},{"location":"core-services/network-status-rest-v1/#esimstatus","title":"ESimStatus","text":"

    The status of an ESIM.

    "},{"location":"core-services/network-status-rest-v1/#beareriptype","title":"BearerIpType","text":"

    The type of Bearer or Context associated to a modem connection.

    "},{"location":"core-services/network-status-rest-v1/#modemconnectiontype","title":"ModemConnectionType","text":""},{"location":"core-services/network-status-rest-v1/#modemconnectionstatus","title":"ModemConnectionStatus","text":"

    The status of a modem.

    "},{"location":"core-services/network-status-rest-v1/#accesstechnology","title":"AccessTechnology","text":"

    The specific technology types used when a modem is connected or registered to a network.

    "},{"location":"core-services/network-status-rest-v1/#registrationstatus","title":"RegistrationStatus","text":"

    The registration status of a modem when connected to a mobile network.

    "},{"location":"core-services/network-status-rest-v1/#failurereport","title":"FailureReport","text":"

    An object reporting a failure while retrieving the status of a specific network interface

    Properties:

    "},{"location":"core-services/network-status-rest-v1/#genericfailurereport","title":"GenericFailureReport","text":"

    An object reporting a failure message.

    Properties:

    "},{"location":"core-services/nvidia-triton-server-inference-engine/","title":"Nvidia\u2122 Triton Server Inference Engine","text":"

    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:

    "},{"location":"core-services/nvidia-triton-server-inference-engine/#nvidiatm-triton-server-installation","title":"Nvidia\u2122 Triton Server installation","text":"

    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:

    "},{"location":"core-services/nvidia-triton-server-inference-engine/#triton-docker-image-installation","title":"Triton Docker image installation","text":"

    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.

    "},{"location":"core-services/nvidia-triton-server-inference-engine/#native-triton-installation-on-supported-devices","title":"Native Triton installation on supported devices","text":"

    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.

    "},{"location":"core-services/nvidia-triton-server-inference-engine/#triton-server-setup","title":"Triton Server setup","text":"

    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:

    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:

    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:

    "},{"location":"core-services/nvidia-triton-server-inference-engine/#ai-model-encryption-support","title":"AI Model Encryption Support","text":"

    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.

    "},{"location":"core-services/nvidia-triton-server-inference-engine/#encryption-procedure","title":"Encryption procedure","text":"

    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.

    "},{"location":"core-services/position-service/","title":"Position Service","text":"

    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, and altitude. In this case, the position 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:

    "},{"location":"core-services/rest-service/","title":"REST Service","text":"

    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:

    "},{"location":"core-services/rest-service/#custom-authentication-methods","title":"Custom authentication methods","text":"

    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.

    "},{"location":"core-services/rest-service/#assets-rest-apis","title":"Assets REST APIs","text":"

    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.

    Method Path Allowed roles Encoding Request parameters Description GET / 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:

    "},{"location":"core-services/sqlite-db-service/","title":"SQLite Db Service","text":"

    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.

    "},{"location":"core-services/sqlite-db-service/#supported-features","title":"Supported Features","text":"

    Kura supports the following SQLite database features:

    "},{"location":"core-services/sqlite-db-service/#usage","title":"Usage","text":""},{"location":"core-services/sqlite-db-service/#creating-a-new-sqlite-database-instance","title":"Creating a new SQLite database instance","text":"

    To create a new SQLite database instance, use the following procedure:

    1. Open the Administrative UI and press the + button in the side menu, under the Services section. A pop-up dialog should appear.
    2. Select org.eclipse.kura.db.SQLiteDbService from the Factory drop-down list, enter an arbitrary name for the new instance and click Apply.
    3. An entry for the newly created instance should appear in the side menu under Services, click on it to review its configuration. It is not possible to create different DB instances that manage the same database file.
    "},{"location":"core-services/sqlite-db-service/#configuration-parameters","title":"Configuration Parameters","text":"

    The SQLite DB provides the following configuration parameters:

    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.

    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.

    "},{"location":"core-services/sqlite-db-service/#selecting-a-database-instance-for-existing-components","title":"Selecting a database instance for existing components","text":"

    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 BLOB

    The 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:

    "},{"location":"gateway-configuration/authentication-and-authorization/","title":"Authentication and authorization","text":"

    Kura 5 introduces a centralized authentication and authorization framework based on the OSGi UserAdmin specification. This framework introduces the concepts of identities and permissions:

    Examples of applications that use the new authentication and authorization framework are the Web Console and the REST API framework:

    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:

    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:

    "},{"location":"gateway-configuration/authentication-and-authorization/#permissions","title":"Permissions","text":"

    A Kura permission is represented as a UserAdmin Group with the following properties:

    Starting from Kura 5.5 the following restrictions will be applied by the IdentityService to the name new permissions:

    "},{"location":"gateway-configuration/authentication-and-authorization/#useradmin-persistence","title":"UserAdmin persistence","text":"

    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.

    "},{"location":"gateway-configuration/authentication-and-authorization/#useradmindictvalue","title":"UserAdminDictValue","text":"

    A value appearing in UserAdmin dictionaries like properties and credentials

    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

    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

    "},{"location":"gateway-configuration/authentication-and-authorization/#user","title":"User","text":"

    An object describing and UserAdmin User

    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

    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 by modem USB address (i.e. 2-1). This 'fake' interface name is completed 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 IPv4 or IPv6 tab, and then setting the Cellular tab. Note that the cellular interface can only be set as WAN using DHCP, Disabled or Not Managed (only for IPv4 connections). 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:

    The GPS tab allows the user to enable or disable the GPS module provided by the cellular modem. The property is:

    "},{"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:

    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:

    {\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:

    1. BIRTH message: sent immediately when device is connected to the cloud platform;
    2. DISCONNECT message: sent immediately before device is disconnected from the cloud platform;
    3. delayed BIRTH message: sent when new cloud application handler becomes available, a DP is installed or removed, or when the GPS position is locked (can be disabled). These messages are cached for 30 seconds before sending. If no other message of such type arrives the message is sent; otherwise the BIRTH is cached and the timeout restarts. This is to avoid sending multiple messages when the framework starts.
    "},{"location":"gateway-configuration/data-service-configuration/","title":"Data Service Configuration","text":"

    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.

    "},{"location":"gateway-configuration/data-service-configuration/#connection-monitors","title":"Connection Monitors","text":"

    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:

    "},{"location":"gateway-configuration/data-service-configuration/#message-publishing-backoff-delay","title":"Message Publishing Backoff Delay","text":"

    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:

    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:

    1. 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.

    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.

    3. 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:

    "},{"location":"gateway-configuration/data-service-configuration/#payload-size-limiting","title":"Payload size limiting","text":"

    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:

    "},{"location":"gateway-configuration/device-information/","title":"Device Information","text":"

    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:

    "},{"location":"gateway-configuration/device-information/#containers","title":"Containers","text":"

    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:

    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 four configuration tabs: IPv4, IPv6, DHCPv4 & NAT and Advanced. Each Ethernet interface may be configured either as LAN or WAN; it may also be disabled.

    If the interface is designated as LAN in the IPv4 tab and is manually configured, the DHCPv4 & NAT tab is enabled to allow DHCP server and/or 'many-to-one' NAT setup; otherwise, the DHCPv4 & NAT tab is disabled.

    For more information on IPv4, IPv6 and DHCPv4 & NAT settings, please refer to the Network Configuration section. For the advanced settings, see the Advanced Settings 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:

    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.

    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:

    The following port forwarding entries are added to the second RaspberryPi configuration as described above using the Port Forward Entry form:

    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:

    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:

    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:

    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:

    "},{"location":"gateway-configuration/gateway-administration-console-authentication/#default-identities","title":"Default identities","text":"

    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.admin

    It 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.

    "},{"location":"gateway-configuration/gateway-administration-console-authentication/#identity-name-and-password","title":"Identity name and password","text":"

    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.

    "},{"location":"gateway-configuration/gateway-administration-console-authentication/#certificate-authentication","title":"Certificate authentication","text":"

    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:

    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:

    "},{"location":"gateway-configuration/gateway-administration-console/#https-related-warnings","title":"HTTPS related warnings","text":"

    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:

    "},{"location":"gateway-configuration/gateway-status/#ethernet-wireless-and-cellular-settings","title":"Ethernet, Wireless, and Cellular Settings","text":"

    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.

    Method Path Roles allowed Encoding Request parameters Description GET / 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/csrkeystoreServicePid=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:

    Method Path Roles allowed Encoding Request parameters Description POST /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:

    "},{"location":"gateway-configuration/keystores-management/#pkcs11keystoreserviceimpl","title":"PKCS11KeystoreServiceImpl","text":"

    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":"

    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:

    "},{"location":"gateway-configuration/network-advanced/#advanced-configuration","title":"Advanced Configuration","text":"

    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.

    "},{"location":"gateway-configuration/network-configuration/","title":"Network Configuration","text":"

    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 IPv4 or IPv6 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 IPv4 and IPv6 tabs contain the following configuration parameters:

    If the network interface is configured as Enabled for LAN and manually configured (i.e., not a DHCP client) in the IPV4 tab, the DHCPv4 & 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-tbd-not-applicable-in-nm","title":"More details about the Not Managed interface Status - (TBD: not applicable in NM)","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.

    Is there at least an interface set as 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.

    "},{"location":"gateway-configuration/network-configuration/#dhcpv4-nat-configuration","title":"DHCPv4 & NAT Configuration","text":"

    The DHCPv4 & 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 DHCPv4 & 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.

    "},{"location":"gateway-configuration/network-configuration/#common-properties","title":"Common properties","text":"Name Type Description Default value 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.

    "},{"location":"gateway-configuration/network-configuration/#ipv4-dhcp-server-properties","title":"IPv4 DHCP Server properties","text":"Name Type Description Default value 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.

    "},{"location":"gateway-configuration/network-configuration/#wifi-master-access-point-properties","title":"WiFi Master (Access Point) properties","text":"Name Type Description Default value 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:

    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.

    "},{"location":"gateway-configuration/network-configuration/#vlan-properties","title":"VLAN properties","text":"Name Type Description Default value 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.

    "},{"location":"gateway-configuration/network-failover/#operating-modes","title":"Operating modes","text":"

    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 Response http://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:

    "},{"location":"gateway-configuration/network-hardware/","title":"Hardware Tab","text":"

    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:

    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:

    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:

    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":"

    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.

    "},{"location":"gateway-configuration/vlan-configuration/#basic-vlan-configuration-example","title":"Basic VLAN configuration example","text":"

    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":"

    To enable the Enterprise Wi-Fi, the Wireless Security property in the Wireless tab has to be set to WPA2/WPA3-Enterprise. This feature is available only if the Wireless Mode is Station Mode. The following is a list of currently supported 802.1x authentication methods.

    "},{"location":"gateway-configuration/wifi-configuration-8021x/#ttls-mschapv2","title":"TTLS-MSCHAPv2","text":"
    1. Set up gateway Wi-Fi as described in the Wi-Fi configuration guide.
    2. Ensure Wireless Security is set to WPA2/WPA3-Enterprise
    3. select the 802.1x tab
    4. Set Enteprise EAP -> TTLS
    5. Set Inner Authentication -> MSCHAPV2
    6. Set Identity (Username)
    7. Set Password
    8. Press 'Apply'

    The configuration should look like the following:

    "},{"location":"gateway-configuration/wifi-configuration-8021x/#peap-mschapv2","title":"PEAP-MSCHAPv2","text":"
    1. Set up gateway Wi-Fi as described in the Wi-Fi configuration guide.
    2. Ensure Wireless Security is set to WPA2/WPA3-Enterprise
    3. select the 802.1x tab
    4. Set Enteprise EAP -> PEAP
    5. Set Inner Authentication -> MSCHAPV2
    6. Set Identity (Username)
    7. Set Password
    8. Press 'Apply'

    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:

    "},{"location":"gateway-configuration/wifi-configuration-8021x/#enrolling-secrets-in-the-keystore-service","title":"Enrolling secrets in the Keystore service.","text":"
    1. Navigate to Security under the System tab.
    2. Under the Keystore Configuration add a new keystore, and keep note of the name.
    3. After the Keystore is created, be sure to change the path to a persistent directory.
    4. Navigate to the Certificate List and create a new Certificate. Insert the PEM and Apply, keep note of the name.
    5. Now press 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.
    "},{"location":"gateway-configuration/wifi-configuration-8021x/#wifi-setup","title":"Wifi Setup","text":"
    1. Set up gateway Wi-Fi as described in the Wi-Fi configuration guide.
    2. Ensure Wireless Security is set to WPA2/WPA3-Enterprise.
    3. Select the 802.1x tab.
    4. Set Enteprise EAP -> TLS.
    5. Set Identity (Username).
    6. Set Keystore Pid to the name of the keystore created above.
    7. Set Certificate Authority Certificate (CA-Cert) to the name of the certificate created above.
    8. Set the 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 IPv4, IPv6 and DHCPv4 & 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.

    "},{"location":"gateway-configuration/wifi-configuration/#wireless-configuration","title":"Wireless Configuration","text":"

    The Wireless tab contains the following configuration parameters:

    "},{"location":"gateway-configuration/wifi-configuration/#wi-fi-station-mode-configuration","title":"Wi-Fi Station Mode Configuration","text":"

    In addition to the options described above, the Wireless configuration display the Access Point Scan button that help to configure Wi-Fi in the Station mode.

    "},{"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.

    "},{"location":"getting-started/docker-quick-start/#command-toolbox","title":"Command Toolbox","text":"

    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.

    "},{"location":"getting-started/install-kura/","title":"Install Kura","text":"

    Eclipse Kura\u2122 is provided using a Debian 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:

    1. standard installers, like kura-6.0.0_generic-arm32_installer.deb; and
    2. installers with suffix nn, like kura-6.0.0_generic-arm32-nn_installer.deb

    Profiles of types (1) ship a Kura version with networking functionalities. In particular, they 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 Kura installers section for further information.

    Installers of type (2) 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:

    "},{"location":"getting-started/install-kura/#kura-installers","title":"Kura installers","text":"

    A user can deploy Kura on a target system using the installer tailored for the device architecture. The installer file looks like:

    kura-<kura-version>_generic-<arch>_installer.deb/rpm\n

    where <arch> is one of the supported architectures: x86_64, arm32, and arm64. Kura can work on systems that have available the dependencies listed in the Kura dependencies section, and that have at least one physical ethernet interface.

    "},{"location":"getting-started/install-kura/#java-heap-memory-assignment","title":"Java Heap Memory Assignment","text":"

    The Eclipse Kura\u2122's installer 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 a profile with network management support, the initial network configuration will be generated dynamically using the rules described below:

    For example, if the system contains the following interfaces: wlp2s0, wlp3s0, enp3s0, eno1, ens2; then eno1 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":"

    The initial firewall configuration will be as shown in the screenshot below.

    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":"

    Eclipse Kura\u2122 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:

    "},{"location":"getting-started/install-kura/#kura-dependencies","title":"Kura dependencies","text":"

    To have all the Kura features working, the following dependencies are required:

    "},{"location":"getting-started/install-kura/#reference-devices","title":"Reference devices","text":"

    Eclipse Kura\u2122 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 Raspberry Pi OS \"Bookworm\" Raspberry Pi 3/4 arm64 Raspberry Pi OS \"Bookworm\" Raspberry Pi 3/4 arm64 Ubuntu 20.04 ZimaBoard/Blade x86_64 TBD NVIDIA Jetson AGX Orin\u2122 arm64 TBD

    Check out the quick start guides for the detailed installation steps and set-up procedures:

    "},{"location":"getting-started/nvidia-jetson-orin-quick-start/","title":"NVIDIA Jetson AGX Orin\u2122 - Quick Start","text":""},{"location":"getting-started/nvidia-jetson-orin-quick-start/#overview","title":"Overview","text":""},{"location":"getting-started/raspberry-pi-raspberryos-quick-start/","title":"Raspberry Pi - Raspberry Pi OS Quick Start","text":""},{"location":"getting-started/raspberry-pi-raspberryos-quick-start/#overview","title":"Overview","text":"

    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:

    1. Boot the Raspberry Pi with the latest\u00a0Raspberry Pi OS image.

    2. 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.

    3. 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

    4. 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

    5. Install Kura with:\u00a0

      sudo apt-get install ./kura-<kura-version>_generic-<arch>_installer.deb\n
    6. 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
    7. (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:

      • Execute on the device the command 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

      • Modify the /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

    8. Reboot the Raspberry Pi with:

      sudo reboot\n

      Kura starts on the target platform after reboot.

    9. 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

    "},{"location":"getting-started/raspberry-pi-ubuntu-20-quick-start/","title":"Raspberry Pi - Ubuntu 20 Quick Start","text":""},{"location":"getting-started/raspberry-pi-ubuntu-20-quick-start/#overview","title":"Overview","text":"

    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

    "},{"location":"getting-started/raspberry-pi-ubuntu-20-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:

    1. Boot the Raspberry Pi with the latest\u00a0Ubuntu 20.04.3 LTS Server image.

    2. Make sure your device is connected to internet. By default, eth0 lan network interface is configured in DHCP mode.

    3. 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

    4. 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

    5. Install Kura with:

      sudo apt install ./kura-<kura-version>_generic-<arch>_installer.deb\n

      All the required dependencies will be downloaded and installed.

    6. 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.

    7. (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
    8. Reboot the Raspberry Pi with:

      sudo reboot\n

      Kura starts on the target platform after reboot.

    9. 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

    "},{"location":"getting-started/zima-board-quick-start/","title":"ZimaBoard/Blade Quick Start","text":""},{"location":"getting-started/zima-board-quick-start/#overview","title":"Overview","text":""},{"location":"java-application-development/configurable-application/","title":"Configurable Application","text":""},{"location":"java-application-development/configurable-application/#overview","title":"Overview","text":"

    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:

    "},{"location":"java-application-development/configurable-application/#prerequisites","title":"Prerequisites","text":""},{"location":"java-application-development/configurable-application/#configurable-component-example","title":"Configurable Component Example","text":""},{"location":"java-application-development/configurable-application/#create-plug-in","title":"Create 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.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:

    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.

    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.configuration.ConfigurableComponent\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:

    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.configuration.ConfigurableComponent\"/>\n    </service>\n    <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.example.configurable.ConfigurableExample\"/>\n</scr:component>\n
    "},{"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:

    "},{"location":"java-application-development/connected-application/#prerequisites","title":"Prerequisites","text":""},{"location":"java-application-development/connected-application/#heater-demo-introduction","title":"Heater Demo Introduction","text":"

    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:

    "},{"location":"java-application-development/connected-application/#acquiring-cloudclient","title":"Acquiring CloudClient","text":"

    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:

    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:

    "},{"location":"java-application-development/contributing/#kura-dev-meeting","title":"Kura Dev Meeting","text":"

    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:

    "},{"location":"java-application-development/deploy-and-debug-applications/#prerequisites","title":"Prerequisites","text":""},{"location":"java-application-development/deploy-and-debug-applications/#testing-the-osgi-plug-in","title":"Testing the OSGi Plug-in","text":"

    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.

    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:

    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:

    1. Copy the deployment package file (*.dp) to the target device, into the folder:

    /opt/eclipse/kura/kura/packages

    1. Edit the dpa.properties file through the vi editor by entering the following command:

    vi /opt/eclipse/kura/kura/dpa.properties

    1. Add an entry in the dpa.properties file to include the new package name, such as:

    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.

    1. Save and close the file using the \u2018:wq\u2019 command.

    2. 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:

    1. Requirements installation
    2. Eclipse Oomph setup
    3. Eclipse Kura maven build
    "},{"location":"java-application-development/development-environment-setup/#requirements","title":"Requirements","text":"

    Before building Eclipse Kura, you need to have the following programs installed in your system:

    Recommended additional software:

    "},{"location":"java-application-development/development-environment-setup/#installing-prerequisites-in-mac-os","title":"Installing Prerequisites in Mac OS","text":"

    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

    If 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).

    "},{"location":"java-application-development/development-environment-setup/#build-scripts","title":"Build scripts","text":"

    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:

    "},{"location":"java-application-development/hello-world-application/#prerequisites","title":"Prerequisites","text":"

    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:

    "},{"location":"java-application-development/hello-world-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 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:

    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:

    Lastly, the Create an Access Point section requires:

    "},{"location":"java-application-development/how-to-manage-network-settings/#determine-your-network-interfaces","title":"Determine Your Network Interfaces","text":"

    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:

    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:

    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.

    "},{"location":"java-application-development/how-to-manage-network-settings/#connect-to-an-access-point","title":"Connect to an Access Point","text":"

    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

    The following source code will also need to be implemented:

    "},{"location":"java-application-development/how-to-manage-network-settings/#meta-infmanifestmf-file","title":"META-INF/MANIFEST.MF File","text":"

    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:

    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:

    "},{"location":"java-application-development/how-to-serial-ports/#prerequisites","title":"Prerequisites","text":""},{"location":"java-application-development/how-to-serial-ports/#serial-communication-with-kura","title":"Serial Communication with Kura","text":"

    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.

    "},{"location":"java-application-development/how-to-serial-ports/#determine-serial-device-nodes","title":"Determine Serial Device Nodes","text":"

    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:

    1. process to export the OSGi bundle will have an additional step,
    2. the actual code in this example will have the following differences:
      • The new Plug-in Project is named \u201corg.eclipse.kura.example.serial\u201d
      • A class named \u201cSerialExample\u201d is created in the org.eclipse.kura.example.serial project
      • The following bundles are included in the Automated Management of Dependencies section in the MANIFEST.MF:
        • javax.comm
        • javax.microedition.io
        • org.eclipse.kura.cloud
        • org.eclipse.kura.comm
        • org.eclipse.kura.configuration
        • org.osgi.service.component
        • org.osgi.service.io
        • org.slf4j

    The following files need to be implemented:

    "},{"location":"java-application-development/how-to-serial-ports/#meta-infmanifestmf-file","title":"META-INF/MANIFEST.MF File","text":"

    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-beacon-apis/","title":"How to Use Beacon APIs","text":""},{"location":"java-application-development/how-to-use-beacon-apis/#overview","title":"Overview","text":"

    Eclipse Kura implements a set of APIs for managing Bluetooth Low Energy and Beacon devices.

    The purpose of the 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.

    "},{"location":"java-application-development/how-to-use-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 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-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-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-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 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-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-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-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-bt-le-apis/","title":"How to Use Bluetooth LE APIs","text":""},{"location":"java-application-development/how-to-use-bt-le-apis/#overview","title":"Overview","text":"

    Eclipse Kura implements a set of APIs for managing Bluetooth Low Energy and Beacon devices.

    The purpose of the 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-bt-le-apis/#bluez-dbus-ble-gatt-api","title":"Bluez-Dbus - BLE GATT API","text":"

    The implementation of the 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-bt-le-apis/#apis-description","title":"APIs description","text":"

    The 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-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 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-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-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-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-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-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-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:

    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

    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.

    "},{"location":"java-application-development/how-to-use-gpio/#openjdk-device-io","title":"OpenJDK Device I/O","text":"

    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-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:

    The ModbusProtocolDevice service also requires a valid Serial Line or Ethernet connection configuration including the following parameters:

    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:

    All functions throw a ModbusProtocolException. Valid exceptions include:

    "},{"location":"java-application-development/how-to-use-modbus/#code-examples","title":"Code Examples","text":"

    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-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:

    "},{"location":"java-application-development/how-to-use-watchdog/#code-example","title":"Code Example","text":"

    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:

    "},{"location":"java-application-development/kura-workspace-setup/#importing-the-eclipse-kura-user-workspace","title":"Importing the Eclipse Kura User Workspace","text":"

    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:

    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:

    1. Large enough to satisfy the requirements of applications running inside Kura.
    2. Small enough so that the requirements of the system and applications running outside Kura are satisfied.

    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.

    "},{"location":"java-application-development/ram-usage-considerations/#logging","title":"Logging","text":"

    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.

    "},{"location":"java-application-development/ram-usage-considerations/#external-application-ram-usage","title":"External application RAM usage","text":"

    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.

    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 \\

    "},{"location":"kura-wires/assets-as-wire-components/","title":"Assets as Wire Components","text":"

    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:

    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:

    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:

    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.

    "},{"location":"kura-wires/assets-as-wire-components/#write-mode","title":"Write mode","text":"

    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:

    The following operations will happen:

    "},{"location":"kura-wires/introduction/","title":"Introduction","text":"

    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:

    "},{"location":"kura-wires/introduction/#wire-composer","title":"Wire Composer","text":"

    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:

    "},{"location":"kura-wires/introduction/#graph-download","title":"Graph Download","text":"

    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.

    "},{"location":"kura-wires/wire-graph-service-configuration-format/#json-definitions","title":"JSON definitions","text":""},{"location":"kura-wires/wire-graph-service-configuration-format/#position","title":"Position","text":"

    An object representing a Wire Component position.

    Properties:

    {\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:

    {\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:

    {\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:

    {\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:

    {\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:

    {\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":""},{"location":"kura-wires/wire-service-references/#master-thesis","title":"Master Thesis","text":""},{"location":"kura-wires/wire-service-references/#conferences-and-slides","title":"Conferences and slides","text":""},{"location":"kura-wires/wire-service-references/#youtube","title":"Youtube","text":""},{"location":"kura-wires/wire-service-rest-v1/","title":"Wire Service V1 REST APIs and MQTT Request Handler","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.

    "},{"location":"kura-wires/wire-service-rest-v1/#request-definitions","title":"Request definitions","text":""},{"location":"kura-wires/wire-service-rest-v1/#getgraphshapshot","title":"GET/graph/shapshot","text":""},{"location":"kura-wires/wire-service-rest-v1/#putgraphsnapshot","title":"PUT/graph/snapshot","text":"

    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":""},{"location":"kura-wires/wire-service-rest-v1/#getdriverspids","title":"GET/drivers/pids","text":""},{"location":"kura-wires/wire-service-rest-v1/#getassetspids","title":"GET/assets/pids","text":""},{"location":"kura-wires/wire-service-rest-v1/#getgraphtopology","title":"GET/graph/topology","text":""},{"location":"kura-wires/wire-service-rest-v1/#postconfigsbypid","title":"POST/configs/byPid","text":""},{"location":"kura-wires/wire-service-rest-v1/#delconfigsbypid","title":"DEL/configs/byPid","text":""},{"location":"kura-wires/wire-service-rest-v1/#putconfigs","title":"PUT/configs","text":""},{"location":"kura-wires/wire-service-rest-v1/#getmetadata","title":"GET/metadata","text":""},{"location":"kura-wires/wire-service-rest-v1/#getmetadatawirecomponentsfactorypids","title":"GET/metadata/wireComponents/factoryPids","text":""},{"location":"kura-wires/wire-service-rest-v1/#getmetadatawirecomponentsdefinitions","title":"GET/metadata/wireComponents/definitions","text":""},{"location":"kura-wires/wire-service-rest-v1/#postmetadatawirecomponentsdefinitionsbyfactorypid","title":"POST/metadata/wireComponents/definitions/byFactoryPid","text":""},{"location":"kura-wires/wire-service-rest-v1/#getmetadatadriversfactorypids","title":"GET/metadata/drivers/factoryPids","text":""},{"location":"kura-wires/wire-service-rest-v1/#getmetadatadriverocds","title":"GET/metadata/driver/ocds","text":""},{"location":"kura-wires/wire-service-rest-v1/#postmetadatadriversocdsbyfactorypid","title":"POST/metadata/drivers/ocds/byFactoryPid","text":""},{"location":"kura-wires/wire-service-rest-v1/#getmetadatadriverschanneldescriptors","title":"GET/metadata/drivers/channelDescriptors","text":""},{"location":"kura-wires/wire-service-rest-v1/#postmetadatadriverschanneldescriptorsbypid","title":"POST/metadata/drivers/channelDescriptors/byPid","text":""},{"location":"kura-wires/wire-service-rest-v1/#getmetadataassetschanneldescriptor","title":"GET/metadata/assets/channelDescriptor","text":""},{"location":"kura-wires/wire-service-rest-v1/#json-definitions","title":"JSON definitions","text":""},{"location":"kura-wires/wire-service-rest-v1/#wirecomponentdefinition","title":"WireComponentDefinition","text":"

    A Wire Component definition object

    Properties:

    {\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:

    {\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:

    {\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):

    In 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:

    "},{"location":"kura-wires/multiport-wire-components/join-component/","title":"Join Component","text":"

    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:

    "},{"location":"kura-wires/multiport-wire-components/mathematical-components-example/#sum","title":"Sum","text":""},{"location":"kura-wires/multiport-wire-components/mathematical-components-example/#difference","title":"Difference","text":""},{"location":"kura-wires/multiport-wire-components/mathematical-components-example/#multiplication","title":"Multiplication","text":""},{"location":"kura-wires/multiport-wire-components/mathematical-components-example/#division","title":"Division","text":""},{"location":"kura-wires/multiport-wire-components/multiport-wire-components/","title":"Multiport Wire Components","text":"

    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:

    "},{"location":"kura-wires/script-components/graalvm-filter-component/#usage","title":"Usage","text":"

    The following global variables are available to the script:

    The following utility functions are available (see Creating and emitting wire records for usage):

    The following global constants expose the org.eclipse.kura.type.DataType enum variants:

    "},{"location":"kura-wires/script-components/graalvm-filter-component/#received-envelope","title":"Received envelope","text":"

    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 WireRecords 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.

    "},{"location":"kura-wires/script-components/graalvm-filter-component/#creating-and-emitting-wire-records","title":"Creating and emitting wire records","text":"

    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 WireRecords. This object contains a list of WireRecords 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:

    "},{"location":"kura-wires/script-components/nashorn-script-filter/#usage","title":"Usage","text":"

    The following global variables are available to the script:

    The following utility functions are available (see Creating and emitting wire records for usage):

    The following global constants expose the org.eclipse.kura.type.DataType enum variants:

    "},{"location":"kura-wires/script-components/nashorn-script-filter/#received-envelope","title":"Received envelope","text":"

    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:

    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:

    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:

    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:

    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":"
    1. Download the OPC-UA server simulator bundle and install it on your Kura instance. It will create a simulated OPC-UA server that exposes some sensors (light, temperature and water sensor) and some actuators (buzzer, led and fan).
    2. In the Kura Administrative Web Interface, select \u201cOPCUA Server demo\u201d in \u201cServices\u201d and set server.port to 1234. Click the Apply button. This will start an OPC-UA\u200b server on port 1234.
    "},{"location":"kura-wires/single-port-wire-components/db-store-and-filter/#configure-wires-opc-ua-application","title":"Configure Wires OPC-UA application","text":"
    1. Install the OPC-UA Driver from Eclipse Kura Marketplace.
    2. Use the local Kura Administrative Web Interface to create a new OPC-UA driver instance:
      • Select Drivers and Assets, click the New Driver button
      • Select org.eclipse.kura.driver.opcua, type in a name, and click Apply: a new service will show up under Services.
    3. Configure the new service as follows:

      • endpoint.ip: localhost
      • endpoint.port: 1234
      • server.name: leave blank
    4. Click on Wires under System

    5. Add a new Timer component and configure the interval at which the OPC-UA server will be sampled
    6. Add a new Asset with the previously added OPC-UA Driver
    7. 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.

    8. Add a new Wire Record Store named DBStore component and configure it as follows:

      • Record Collection Name: WR_data
      • Maximum Record Collection Size: 10000
      • Cleanup Records Keep: 0
      • WireRecordStoreProvider Target Filter : the Wire Record Store Provider pid to be used
    9. Add a new Publisher component and configure the chosen cloud platform stack in cloud.service.pid option
    10. Add Logger component
    11. Add another instance of Timer
    12. Add a new Wire Record Query component named DBFilter component and configure it as follows. The query will get the values from the light sensor and if they are less than 200, the fan is activated.
      • Query: SELECT (CASE WHEN \u201clight\u201d < 200 THEN 1 ELSE 0 END) AS \u201cled\u201d FROM \u201cWR_data\u201d ORDER BY TIMESTAMP DESC LIMIT 1;
      • Cache Expiration Interval (Seconds): 0
      • QueryableWireRecordStoreProvider Target Filter : the Queryable Wire Record Store Provider pid to be used
    13. 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.

    14. 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.

    "},{"location":"kura-wires/single-port-wire-components/fifo-component/","title":"FIFO Component","text":"

    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:

    1. 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.

    2. 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:

    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.

    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":"
    1. Install the Eddystone\u2122 driver from the Eclipse Kura Marketplace.

    2. On the Kura Web Interface, instantiate an Eddystone\u2122 Driver:

      • Under System, select Drivers and Assets and click on the New Driver button.
      • Select org.eclipse.kura.driver.eddystone as Driver Factory, type a name in to Driver Name and click Apply: a new driver will be instantiated and shown up under the Drivers and Assets tab.
      • Configure the new driver setting the bluetooth interface name (e.g. hci0).
    3. From the Drivers and Assets tab, add a new asset bound to the Eddystone\u2122 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 Eddystone\u2122 driver.

      • Click on the new asset and configure it, adding the channels. Each channel represents a type of frame the Driver is interested to. Please note that in the above picture two channels are created: one for the UID type and the second for the URL. In this example only the URL will be used.
      • Check the listen checkbox for both channels.
      • Click \"Apply\".
    4. Click on Wires under System.

    5. Add a new Asset with the previously added Eddystone asset.

    6. 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
    7. Add Logger component and set the log.verbosity to VERBOSE.

    8. Connect the Asset to the Filter and this to the Logger.

    9. 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
    "},{"location":"kura-wires/usage-examples/gpio-driver-application/","title":"GPIO Driver Application","text":"

    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":"
    1. Install the GPIO Driver from the Eclipse Kura Marketplace.

    2. On the Kura web interface, instantiate a GPIO Driver:

      • Under \"System\", select \"Drivers and Assets\" and click on the \"New Driver\" button.
      • Select \"org.eclipse.kura.driver.gpio\" as \"Driver Factory\", type a name in to \"Driver Name\" and click \"Apply\": a new driver will be instantiated and shown up under the \"Drivers and Assets\" tab.
    3. From the \"Drivers and Assets\" tab, add a new asset bound to the GPIO 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 GPIO driver.
      • Click on the new asset and configure it, adding only one channel called LED as shown in the following picture:

      • Click \"Apply\".
    4. As in point 3., create a new asset as shown below:

      • Click \"Apply\".
    5. Click on \"Wires\" under \"System\".

    6. Add a new \"Timer\" component and configure the interval at which the LED will be toggled.

    7. 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
    8. Add the \"Asset\" created at point 3 and connect the \"Timer\" to the \"Filter\" and the latter to the \"Asset\".

    9. Add the \"Asset\" created at point 4.

    10. Add \"Logger\" component and set log.verbosity to \"VERBOSE\".

    11. Connect the latter \"Asset\" to the \"Logger\". The resulting Wire Graph should be as below:

    12. 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
    "},{"location":"kura-wires/usage-examples/ibeacon-driver-application/","title":"iBeacon\u2122 Driver Application","text":"

    As presented in the iBeacon\u2122 Driver, Kura provides a specific driver that can be used to listen for iBeacons packets.

    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":"
    1. Install the iBeacon driver from the Eclipse Kura Marketplace.

    2. On the Web Interface, instantiate the iBeacon Driver:

      • Under \"System\", select \"Drivers and Assets\" and click on the \"New Driver\" button.
      • Select \"org.eclipse.kura.driver.ibeacon\" as \"Driver Factory\", type a name in to \"Driver Name\" and click \"Apply\": a new driver will be instantiated and shown up under the \"Drivers and Assets\" tab.
      • Configure the new driver setting the bluetooth interface name (e.g. hci0).
    3. 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 \"Apply\".

    4. Click on \"Wires\" under \"System\".

    5. Add a new \"Asset\" with the previously added iBeacon asset.

    6. 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
    7. Add \"Logger\" component and set the log.verbosity to VERBOSE

    8. Connect the \"Asset\" to the \"Filter\" and this to the \"Logger\".
    9. 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
    "},{"location":"kura-wires/usage-examples/opcua-application/","title":"OPC-UA Application","text":"

    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":"
    1. Download the OPC-UA server simulator bundle and install it on Kura. It will create a simulated OPC-UA server that exposes some sensors (light, temperature and water sensor) and some actuators (buzzer, led and fan).
    2. On the Kura web interface, select OPCUA Server demo in Services and set server.port to 1234. Click the Apply button. This will start an OPC-UA server on port 1234.
    "},{"location":"kura-wires/usage-examples/opcua-application/#configure-wires-opc-ua-application","title":"Configure Wires OPC-UA application","text":"
    1. Install the OPC-UA driver from Eclipse Kura Marketplace.
    2. Use the local Kura Administrative Web Interface to create a new OPC-UA driver instance:
      • Select Drivers and Assets, click the New Driver button
      • Select org.eclipse.kura.driver.opcua, type in a name, and click Apply: a new service will show up under Services.
    3. Configure the new service as follows:
      • endpoint.ip: localhost
      • endpoint.port: 1234
      • server.name: leave blank
    4. Click on Wires under System
    5. Add a new Timer component and configure the interval at which the OPC-UA server will be sampled
    6. Add a new Asset with the previously added OPC-UA driver
    7. Configure the new OPC-UA asset, adding new Channels as shown in the following image.
    8. Add a new Publisher component and configure the chosen cloud platform stack in cloud.service.pid option
    9. Add a Logger component
    10. Connect the Timer to the Asset, and the Asset to the Publisher and Logger as shown in the image below.
    11. Click on Apply and check the logs and the cloud platform in order to verify that the data is correctly published.
    "},{"location":"kura-wires/usage-examples/ti-sensortag-application/","title":"TI SensorTag Application","text":"

    As presented in the Ti SensorTag Driver, Kura provides a specific driver that can be used to interact with Texas Instruments SensorTag devices.

    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":"
    1. Install the TI SensorTag driver from the Eclipse Kura Marketplace

    2. On the Kura Administrative Web Interface, instantiate a SensorTag Driver:

      • Under System, select Drivers and Assets and click on the New Driver button.
      • Select 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.
      • Select the newly created Driver instance and configure the Bluetooth interface name (i.e. hci0).

    3. In the Drivers and Assets tab add a new asset and associate it to the SensorTag driver:

    4. Click on the New Asset button and fill the form with the Asset Name, selecting the driver created at point 2. Click Apply and a new asset will be listed.
    5. Click on the new asset and configure it, adding the channels. Each channel represents a single sensor on the SensorTag and it can be chosen from the sensor.name menu. Fill the sensortag.address with the DB address of the SensorTag you want to connect to. The value.type should be set to double, but also the other choices are possible.
    6. Click Apply.

    7. Apply the following configuration for the Asset instance:

    8. 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.

    "},{"location":"quality-assurance/intro/","title":"Introduction","text":""},{"location":"quality-assurance/intro/#eclipsetm-kura-qa","title":"Eclipse\u2122 Kura QA","text":"

    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":""},{"location":"quality-assurance/system-testing/#os","title":"OS","text":""},{"location":"quality-assurance/system-testing/#java","title":"Java","text":""},{"location":"quality-assurance/unit-testing/","title":"Unit Testing","text":""},{"location":"quality-assurance/unit-testing/#build-time-testing","title":"Build-time testing","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.

    "},{"location":"quality-assurance/unit-testing/#code-conventions","title":"Code Conventions","text":""},{"location":"quality-assurance/unit-testing/#running-the-tests","title":"Running the Tests","text":"

    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.

    "},{"location":"quality-assurance/unit-testing/#code-conventions_1","title":"Code Conventions","text":""},{"location":"quality-assurance/unit-testing/#running-the-tests_1","title":"Running the Tests","text":"

    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":""},{"location":"references/mqtt-namespace/","title":"MQTT Namespace","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 Description account_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:

    A requester (i.e., the remote server) initiates a request/response conversation through the following events:

    1. Generating a conversation identifier known as a request.id (e.g., by concatenating a random number to a timestamp)

    2. 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
    3. Sending the request message to the appropriate application-specific topic with the following fields in the payload:

      • request.id (identifier used to match a response with a request)
      • requester.client.id (client ID of the requester)

    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:

    The gateway device replies with a response message similar to the following:

    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:

    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 \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.

    "},{"location":"references/mqtt-namespace/#read-configuration-for-a-given-service","title":"Read Configuration for a Given Service","text":"

    This operation provides configurations for a specific service that is identified by an OSGi service persistent identifier pid.

    "},{"location":"references/mqtt-namespace/#update-all-configurations","title":"Update All Configurations","text":"

    This operation remotely updates the configuration of a set of services.

    "},{"location":"references/mqtt-namespace/#update-the-configuration-of-a-given-service","title":"Update the Configuration of a Given Service","text":"

    This operation remotely updates the configuration of the service identified by a pid.

    "},{"location":"references/mqtt-namespace/#example-management-web-application","title":"Example Management Web Application","text":"

    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:

    "},{"location":"references/mqtt-namespace/#deploy-v2","title":"DEPLOY-V2","text":""},{"location":"references/mqtt-namespace/#download-and-install-messages","title":"Download and Install Messages","text":"

    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:

    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.

    The verifier script can be provided in the following ways:

    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: