{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["img"]},"type":"markdown"},"seo":{"title":"Migration Guide:","description":"Accelerate E&P application development and protect your innovation by consuming our Data and Domain APIs / Platform APIs.","lang":"en-US","meta":[{"name":"robots","content":"noindex"}],"llmstxt":{"hide":true,"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"migration-guide","__idx":0},"children":["Migration Guide:"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["While largely similar in architectures, the IIoT SDK version 3.0 has certain differences from earlier versions. The major changes are"," ","in the use of NATS instead of MQTT and runtime updates of application configuration through Twin Properties instead of files on disk."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"overview-of-architectures","__idx":1},"children":["Overview of Architectures"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"1-sdk-20-and-earlier","__idx":2},"children":["1. SDK 2.0 and earlier"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"img","attributes":{"src":"/assets/sdk_2_0_architecture.162798f20fabcff9f136d7587e4d7238b3750061e9f564af10f3006729907251.34151e65.png","alt":"SDK 2"},"children":[]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"2-sdk-30","__idx":3},"children":["2. SDK 3.0"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"img","attributes":{"src":"/assets/sdk_3_0_architecture.f41ddcc5c763908bcf0866e2300d415e5e02dd829aa67948b91adfcbb8a15c05.34151e65.png","alt":"SDK 3"},"children":[]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"overview-of-changes","__idx":4},"children":["Overview of Changes"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"1-using-nats-as-message-broker","__idx":5},"children":["1. Using NATS as Message Broker"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["In earlier versions of the SDK, the primary message broker was MQTT. And even though NATS could be used to send and recieve messages, this was done indirectly via MQTT."," ","Starting with version 3.0, the primary, and only, message broker is NATS while MQTT was completely removed. This enhances clarity and provides applications more granular control of topics to which they wish to subscribe."," ","Furthermore, this removes the need to use the AEA Broker and its accompanying routes.json which were required."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"2-runtime-configuration-updates-via-twins","__idx":6},"children":["2. Runtime Configuration Updates via Twins"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Application configurations files, such as the AEA.json, were updated by uploading a new version to a directory in a docker volume where applications listened for changes. In SDK 3.0, this is no longer the case."," ","Now, at runtime, if an application wishes to update the initial configuration file it is bundled with, it can simply use the cloud Twins REST API to set the configuration in Redis. Applications will no longer have"," ","to update configuration files on disk, nor would they be able to use the FileKey or Commandline mechanisms of updating configuration files. This allows a frictionless update of configuration files at runtime."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following Twins cloud REST API is used to push the new configuration:"]},{"$$mdtype":"Tag","name":"Image","attributes":{"src":"/assets/twins_rest_api.ff19868e2d67e331d99a5c6b5ddd342152b1a665d604409dfe71c52971d8eb26.34151e65.png","alt":"image.png","withLightbox":true,"width":"","height":""},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["An example invocation is shown below:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"curl","header":{"controls":{"copy":{}}},"source":"curl -X 'PUT' \\\n  'https://api-iiot-cloud.app.evd-2.lightops.slb.com/api/twin-properties/v1/slb/evd/SE10i-MJ0LENW3/twin-properties' \\\n  -H 'accept: application/json' \\\n  -H 'Content-Type: application/json' \\\n  -H 'Authorization: Bearer 'Token' \\\n  -d '{\n  \"group\": \"config\",\n  \"twins\": [\n    {\n      \"name\": \"model_text\",\n      \"value\": \"{\\\"head_model_text\\\":\\\"Testing New Test\\\",\\\"pi_model_text\\\":\\\"Sample Text\\\",\\\"WellTestWaterCut_pct\\\":54,\\\"WellTestGOR_raw\\\":24,\\\"WellTestAPI_dAPI\\\":13,\\\"HeadCalibrationThreshold_pct\\\":3,\\\"PICalibrationThreshold_pct\\\":3}\"\n    }\n  ]\n}\n","lang":"curl"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Once the property is set, the following Redis key will hold the new configuration:"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["twin_properties/config/desired/model_text"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["And since the SDK has a subscription on this key, whenever its value is updated, the application is notified of the new configuration."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"3-consolidation-of-config-and-message-routing","__idx":7},"children":["3. Consolidation of Config and Message Routing"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Application configuration has been streamlined by removing the dependency on the AEA Broker. Consequently, message routing information previously stored in routes.json is now consolidated in the single AEA.json config file."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Below are examples of configuration files in SDK 2.0."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Route.json"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"Routes\": [\n    \"/AgoraCoreBusSender/RequestOut TO /aea2-file-manager/RequestIn\",\n    \"/aea2-file-manager/RequestOut TO /AgoraCoreBusSender/RequestIn\",\n    \"/aea2-twin-property-mapper/RequestOut TO /AgoraCoreBusSender/RequestIn\",\n    \"/AgoraCoreBusSender/RequestOut TO /aea2-twin-property-mapper/RequestIn\",\n    \"/AgoraCoreBusSender/RequestOut TO /AEAOpsAgent/RequestIn\",\n    \"/AEAOpsAgent/RequestOut TO /AgoraCoreBusSender/RequestIn\",\n    \"/AEAOpsAgent/EventOut TO /PassThroughHandler/EventIn\",\n    \"/PassThroughHandler/DataOut TO /AgoraCoreBusSender/DataIn\"\n  ]\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AEA.json"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n    \"Name\": \"chemical_injection\",\n    \"AEA2\": {\n        \"LogLevel\": \"Info\",\n        \"BusClient\": {\n            \"Server\": \"mqtt-net-server\",\n            \"Port\": 707,\n            \"Subscriptions\": [\n                \"RequestIn\",\n                \"DataIn\"\n            ]\n        }\n    }\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["In SDK 3.0, both files are now consolidated in a single config file as shown below."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AEA.json"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n    \"Name\": \"MyApp\",\n    \"AEA2\": {\n            \"RedisClient\": {\n            \"Server\": \"localhost\",\n            \"Port\": \"6379\",\n        },\n        \"BusClient\": {\n            \"Server\": \"nats://localhost:4222\",\n            \"Subscriptions\": [\n                {\n                    \"DataIn\": [\n                        \"slbapps.MyApp.DataIn\",\n                        \"slbapps.events.DataIn\"\n                    ]\n                },\n                {\n                    \"RequestIn\": [\n                        \"slbapps.MyApp.RequestIn\"\n                    ]\n                },\n                {\n                    \"EventIn\": [\n                        \"slbapps.MyApp.EventIn\"\n                    ]\n                }\n            ],\n            \"Targets\": [\n                {\n                    \"DataOut\": [\n                        \"slbapps.app1.DataIn\",\n                        \"slbapps.app2.DataIn\",\n                    ]\n                },\n                {\n                    \"RequestOut\": [\n                        \"slbapps.app1.RequestIn\",\n                        \"slbapps.app2.RequestIn\",\n                    ]\n                },\n                {\n                    \"EventOut\": [\n                        \"slbapps.app1.EventIn\",\n                        \"slbapps.app2.EventIn\",\n                    ]\n                }\n            ]\n        }\n    }\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"4-new-metadata-field-in-iopoint","__idx":8},"children":["4. New ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MetaData"]}," field in IoPoint"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A Metadata field was added to SDK 3.0 and also backported to SDK 2.0. The optional field, which is a dictionary of name/value pairs, can be used by applications to"," ","propagate any additional information about the point. For example, and since the SDK is not units aware, any information about units of measure may be stored in the Metadata field."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"    Represents an individual Input/Output (IO) point. Contains information about the value represented \n    as either a flow or a str, quality, and timestamp of the point.\n    \"\"\"\n  \n    def __init__(self,\n                 value: float = None,\n                 value_str: str = None,\n                 quality_code: int = None,\n                 timestamp: float = None,\n                 metadata: dict = None):\n        \"\"\"\n        Initialize an IoPoint instance.\n","lang":"python"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"5-handling-units-of-measure","__idx":9},"children":["5. Handling Units of Measure"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["In general, all versions of the SDK are units unaware. This means applications may send data with or without units, and even with incorrect units. The SDK does not validate nor convert a unit to or from any other unit."," ","With this flexibility there is potential for issues arising during integration with downstream systems."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["In order to reduce the likelihood of such issues, it is recommended that applications use the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Metadata"]}," field in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["IoPoint"]}," ","to propagate unit of measure information using the key ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["uom"]},". For example, a wellhead pressure measurement may be sent in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Metadata"]}," as follows:"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Metadata"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"uom\": \"pressure:psi\",\n  \"prop\": \"value\"\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Applications can propagate unit of measure information according to the unit catalogs used by downstream systems with which they wish to integrate."]}]},"headings":[{"value":"Migration Guide:","id":"migration-guide","depth":1},{"value":"Overview of Architectures","id":"overview-of-architectures","depth":3},{"value":"1. SDK 2.0 and earlier","id":"1-sdk-20-and-earlier","depth":3},{"value":"2. SDK 3.0","id":"2-sdk-30","depth":3},{"value":"Overview of Changes","id":"overview-of-changes","depth":3},{"value":"1. Using NATS as Message Broker","id":"1-using-nats-as-message-broker","depth":3},{"value":"2. Runtime Configuration Updates via Twins","id":"2-runtime-configuration-updates-via-twins","depth":3},{"value":"3. Consolidation of Config and Message Routing","id":"3-consolidation-of-config-and-message-routing","depth":3},{"value":"4. New MetaData field in IoPoint","id":"4-new-metadata-field-in-iopoint","depth":3},{"value":"5. Handling Units of Measure","id":"5-handling-units-of-measure","depth":3}],"frontmatter":{"seo":{"title":"Migration Guide:"}},"lastModified":"2026-01-14T00:18:30.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/solutions/agora/migrationguide","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}