Scenario: Setting Up Resources for IoT Flow Runtime Scenarios

Create the common IoT resources used in the following Flow Runtime scenarios, complete this setup once so that you can reuse these IoT resources for the following scenarios.

The example deployment has one directly connected gateway, two indirectly connected HVAC devices, and two indirectly connected Boiler devices.

The scenarios use this path: an external MQTT broker, Object Storage, or an OCI IoT queue sends data to Node-RED in an IoT Flow Runtime. The flow then publishes to the OCI IoT device host or to an OCI Notifications topic.

Network Setup for the Scenarios

Each scenario uses the following network setup.

Scenario or access path Connections Network setup
Scenario: Ingest live data from an external broker External MQTT broker and OCI IoT device host Use a private subnet with an outbound route through a NAT gateway, or another approved internet egress path. Permit outbound MQTT TLS traffic on TCP port 8883 to the broker and the device host.
Scenario: Ingesting Batch Data from Object Storage OCI Object Storage and OCI IoT device host Provide OCI service connectivity to Object Storage and permit outbound MQTT TLS traffic on TCP port 8883 to the device host. Create the Flow Runtime dynamic group, and configure the Object Storage node to use a Resource Principal with the Object Storage read policy for the scenario bucket. A public subnet or public load balancer isn't required.
Scenario: Monitoring Normalized IoT Data and Sending Email Alerts OCI IoT database queue and OCI Notifications Provide OCI service connectivity to the IoT database queue, the Notifications service, and the IoT command service. Configure the OCI Notification and IoT Send Command nodes to use a Resource Principal with the Notifications policy and the digital twin command-invoke policy. A public MQTT broker, public subnet, or public load balancer isn't required.
Node-RED UI and flow-document management Flow Runtime host and OCI service APIs Open the Node-RED editor from the Flow Runtime and manage the flows document by using the Console, CLI, or API. These management paths are separate from the flow-originated MQTT and OCI service connections.
Note

File Storage isn't used in the Scenario: Ingesting Batch Data from Object Storage. For a different flow that explicitly uses a File Storage mount, ensure that the selected subnet can reach the mount target and that its security rules permit the required File Storage traffic, see Configuring File Storage Access for an IoT Flow Runtime.

Resource Names and Tools

The flow runtime scenarios use the following names. If you use different names, update every corresponding topic, external key, and flow value.

ResourceExample value
Domain groupFR-GUIDE-DG
IoT domainfr-guide-domain
Gateway display nameFR-GUIDE-GW-01
Gateway external keyfr-guide-gw-01
HVAC display namesFR-GUIDE-HVAC-01 and FR-GUIDE-HVAC-02
HVAC external keysfr-guide-hvac-01 and fr-guide-hvac-02
Boiler display namesFR-GUIDE-BOILER-01 and FR-GUIDE-BOILER-02
Boiler external keysfr-guide-boiler-01 and fr-guide-boiler-02
Public MQTT brokertest.mosquitto.org
Public MQTT TLS port8883
Single-runtime topicsource/+/+
Shared-subscription topic$share/fr-guide/source/+/+

You need access to the Node-RED editor for the Flow Runtime, and an MQTT client such as MQTTX.

Create an MQTTX connection with these settings:

FieldValue
Namefr-guide-public-broker
Hosttest.mosquitto.org
Port8883
SSL/TLSEnabled
ProtocolMQTT 5.0
Username and passwordLeave blank

Placeholder Values

Description of the placeholder values in this example.

PlaceholderDescription
<compartment-ocid>Compartment for the IoT resources.
<iot-domain-group-ocid>IoT domain group OCID.
<iot-domain-ocid>IoT domain OCID.
<device-host>Device host for the IoT domain, see Getting an IoT Domain's Details
<subnet-ocid>Subnet used by a Flow Runtime that needs customer network access.
<nsg-ocid>Network security group used by a Flow Runtime that needs customer network access.
<object-storage-namespace>Object Storage namespace for the batch data scenario.
<bucket-name>Object Storage bucket containing the batch CSV objects.
<notification-topic-ocid>OCI Notifications topic OCID for the monitoring scenario.
<domain-short-id>First label of the IoT domain device host. See Getting an IoT Domain's Details.
<flow-runtime-short-id>First label of the Flow Runtime host.
<secret-or-certificate-ocid>Vault secret or certificate OCID used to authenticate the gateway.
<gateway-adapter-ocid>OCID of the gateway digital twin adapter.
<hvac-adapter-ocid>OCID of the HVAC digital twin adapter.
<boiler-adapter-ocid>OCID of the Boiler digital twin adapter.
<gateway-instance-ocid>OCID of the gateway digital twin instance.
<hvac-01-digital-twin-ocid>OCID of the first HVAC digital twin instance.
<hvac-02-digital-twin-ocid>OCID of the second HVAC digital twin instance.
<boiler-01-digital-twin-ocid>OCID of the first Boiler digital twin instance.
<boiler-02-digital-twin-ocid>OCID of the second Boiler digital twin instance.

Step 1: Create Digital Twin Models

Create digital twin models for gateway health telemetry, HVAC telemetry, and Boiler temperature and pressure telemetry. Save the following specifications as gateway-model.json, hvac-model.json, and boiler-model.json.

gateway-model.json
{
  "@context": [
    "dtmi:dtdl:context;3",
    "dtmi:dtdl:extension:historization;1"
  ],
  "@id": "dtmi:com:oracle:iot:flowruntime:GatewayGuide;1",
  "@type": "Interface",
  "displayName": "Flow Runtime Gateway Guide Model",
  "contents": [
    {"@type": ["Telemetry", "Historized"], "name": "cpuUtilization", "schema": "integer"},
    {"@type": ["Telemetry", "Historized"], "name": "memoryUtilization", "schema": "integer"},
    {"@type": ["Telemetry", "Historized"], "name": "storageUtilization", "schema": "integer"},
    {"@type": ["Telemetry", "Historized"], "name": "firmwareVersion", "schema": "string"}
  ]
}
hvac-model.json
{
  "@context": [
    "dtmi:dtdl:context;3",
    "dtmi:dtdl:extension:historization;1"
  ],
  "@id": "dtmi:com:oracle:iot:flowruntime:HVACGuide;1",
  "@type": "Interface",
  "displayName": "Flow Runtime HVAC Guide Model",
  "contents": [
    {"@type": ["Telemetry", "Historized"], "name": "temperature", "schema": "double"},
    {"@type": ["Telemetry", "Historized"], "name": "humidity", "schema": "double"},
    {"@type": ["Telemetry", "Historized"], "name": "pressure", "schema": "double"},
    {"@type": ["Telemetry", "Historized"], "name": "mode", "schema": "string"}
  ]
}
boiler-model.json
{
  "@context": [
    "dtmi:dtdl:context;3"
  ],
  "@id": "dtmi:com:oracle:example:boiler;1",
  "@type": "Interface",
  "displayName": "Boiler",
  "description": "A digital twin model for Boiler",
  "contents": [
    {
      "@type": "Telemetry",
      "name": "temperature",
      "schema": "integer"
    },
    {
      "@type": "Telemetry",
      "name": "pressure",
      "schema": "integer"
    }
  ]
}

Each gateway and HVAC message produces four normalized rows. Each Boiler message produces two normalized rows, one each for temperature and pressure.

    1. On the IoT domains list page, select the IoT domain you want to work with. If you need help finding the list page, see Listing IoT Domains.
    2. Select Digital twin models, and then select Create.
    3. Enter a name for the gateway model, upload gateway-model.json or paste its specification, and then select Create.
    4. Repeat the preceding steps for hvac-model.json and boiler-model.json.
  • Use the oci iot digital-twin-model create command to create all three digital twin models.

    oci iot digital-twin-model create \
      --iot-domain-id <iot-domain-ocid> \
      --spec file://gateway-model.json
    
    oci iot digital-twin-model create \
      --iot-domain-id <iot-domain-ocid> \
      --spec file://hvac-model.json
    
    oci iot digital-twin-model create \
      --iot-domain-id <iot-domain-ocid> \
      --spec file://boiler-model.json
  • Run the CreateDigitalTwinModel operation for gateway-model.json, hvac-model.json, and boiler-model.json. Specify the IoT domain OCID and the corresponding DTDL specification in each request.

Step 2: Create Digital Twin Adapters

Create a digital twin adapter for each model. Save the following definitions as gateway-envelope.json, gateway-routes.json, hvac-envelope.json, hvac-routes.json, boiler-envelope.json, and boiler-routes.json.

gateway-envelope.json
{
  "referenceEndpoint": "/data",
  "referencePayload": {
    "dataFormat": "JSON",
    "data": {
      "time": 1773768299143534,
      "cpuUtil": 30,
      "memUtil": 25,
      "diskUtil": 20,
      "firmware": "Oracle Linux 9.1"
    }
  },
  "envelopeMapping": {
    "timeObserved": "$.time",
    "target": "${if ([\"boilers\", \"hvacs\"] | contains([endpoint(1)])) then endpoint(2) else null end}",
    "contentRoot": "$"
  }
}
gateway-routes.json
[
  {
    "condition": "${endpoint(1) == \"data\"}",
    "referencePayload": {
      "dataFormat": "JSON",
      "data": {
        "time": 1773768299143534,
        "cpuUtil": 30,
        "memUtil": 25,
        "diskUtil": 20,
        "firmware": "Oracle Linux 9.1"
      }
    },
    "payloadMapping": {
      "$.cpuUtilization": "$.cpuUtil",
      "$.memoryUtilization": "$.memUtil",
      "$.storageUtilization": "$.diskUtil",
      "$.firmwareVersion": "$.firmware"
    }
  }
]
hvac-envelope.json
{
  "referenceEndpoint": "/data",
  "referencePayload": {
    "dataFormat": "JSON",
    "data": {
      "time": 1773768299143534,
      "temperature": 72,
      "humidity": 45,
      "pressure": 101.2,
      "mode": "cool"
    }
  },
  "envelopeMapping": {
    "timeObserved": "$.time"
  }
}
hvac-routes.json
[
  {
    "condition": "*",
    "referencePayload": {
      "dataFormat": "JSON",
      "data": {
        "time": 1773768299143534,
        "temperature": 72,
        "humidity": 45,
        "pressure": 101.2,
        "mode": "cool"
      }
    },
    "payloadMapping": {
      "$.temperature": "$.temperature",
      "$.humidity": "$.humidity",
      "$.pressure": "$.pressure",
      "$.mode": "$.mode"
    }
  }
]
boiler-envelope.json
{
  "referenceEndpoint": "/telemetry",
  "referencePayload": {
    "dataFormat": "JSON",
    "data": {
      "timestamp": 1773768299143534,
      "temperature": 0,
      "pressure": 0
    }
  },
  "envelopeMapping": {
    "timeObserved": "$.timestamp"
  }
}
boiler-routes.json
[
  {
    "condition": "*",
    "payloadMapping": {
      "$.temperature": "$.temperature",
      "$.pressure": "$.pressure"
    }
  }
]

The gateway target mapping delegates messages published to hvacs/<external-key> or boilers/<external-key> to the matching indirectly connected digital twin instance.

    1. On the IoT domain details page, select Digital twin adapters, and then select Create.
    2. Enter a name for the gateway adapter and select the gateway model.
    3. Upload or paste gateway-envelope.json as the inbound envelope and gateway-routes.json as the inbound routes, and then select Create.
    4. Create the HVAC adapter by selecting the HVAC model and using hvac-envelope.json and hvac-routes.json.
    5. Create the Boiler adapter by selecting the Boiler model and using boiler-envelope.json and boiler-routes.json.
    6. Record the OCID of each digital twin adapter.
  • Use the oci iot digital-twin-adapter create command to create all three digital twin adapters.

    oci iot digital-twin-adapter create \
      --iot-domain-id <iot-domain-ocid> \
      --display-name "FR Guide Gateway Adapter" \
      --digital-twin-model-spec-uri "dtmi:com:oracle:iot:flowruntime:GatewayGuide;1" \
      --inbound-envelope file://gateway-envelope.json \
      --inbound-routes file://gateway-routes.json
    
    oci iot digital-twin-adapter create \
      --iot-domain-id <iot-domain-ocid> \
      --display-name "FR Guide HVAC Adapter" \
      --digital-twin-model-spec-uri "dtmi:com:oracle:iot:flowruntime:HVACGuide;1" \
      --inbound-envelope file://hvac-envelope.json \
      --inbound-routes file://hvac-routes.json
    
    oci iot digital-twin-adapter create \
      --iot-domain-id <iot-domain-ocid> \
      --display-name "FR Guide Boiler Adapter" \
      --digital-twin-model-spec-uri "dtmi:com:oracle:example:boiler;1" \
      --inbound-envelope file://boiler-envelope.json \
      --inbound-routes file://boiler-routes.json

    Record the OCID returned for each digital twin adapter.

  • Run the CreateDigitalTwinAdapter operation for the gateway, HVAC, and Boiler adapters. In each request, specify the IoT domain OCID, the corresponding model specification URI, inbound envelope, and inbound routes. Record the OCID returned for each adapter.

Step 3: Create Digital Twin Instances

Create the directly connected gateway digital twin instance first, and then create two indirectly connected HVAC and two indirectly connected Boiler digital twin instances. The example flows authenticate to the device host as fr-guide-gw-01.

    1. On the IoT domain details page, select Digital twin instances, and then select Create.
    2. Create the gateway with display name FR-GUIDE-GW-01, external key fr-guide-gw-01, connectivity type Gateway, the gateway adapter, and a device authentication ID.
    3. Record the gateway digital twin instance OCID and device password.
    4. Create an indirectly connected instance with display name FR-GUIDE-HVAC-01 and external key fr-guide-hvac-01.
    5. Select the HVAC adapter and associate the digital twin instance with the gateway.
    6. Repeat the preceding step for FR-GUIDE-HVAC-02 and external key fr-guide-hvac-02.
    7. Create an indirectly connected instance with display name FR-GUIDE-BOILER-01 and external key fr-guide-boiler-01. Select the Boiler adapter and associate the instance with the gateway.
    8. Repeat the preceding step for FR-GUIDE-BOILER-02 and external key fr-guide-boiler-02.
    9. Record the IoT domain device host. To find the device host for an existing IoT domain, see Getting an IoT Domain's Details.
  • Use the oci iot digital-twin-instance create command to create the gateway first.

    oci iot digital-twin-instance create \
      --iot-domain-id <iot-domain-ocid> \
      --display-name FR-GUIDE-GW-01 \
      --connectivity-type GATEWAY \
      --external-key fr-guide-gw-01 \
      --auth-id <secret-or-certificate-ocid> \
      --digital-twin-adapter-id <gateway-adapter-ocid>

    Record the gateway instance OCID, and then create the indirectly connected HVAC and Boiler instances.

    oci iot digital-twin-instance create \
      --iot-domain-id <iot-domain-ocid> \
      --display-name FR-GUIDE-HVAC-01 \
      --connectivity-type INDIRECT \
      --external-key fr-guide-hvac-01 \
      --gateways '["<gateway-instance-ocid>"]' \
      --digital-twin-adapter-id <hvac-adapter-ocid>
    
    oci iot digital-twin-instance create \
      --iot-domain-id <iot-domain-ocid> \
      --display-name FR-GUIDE-HVAC-02 \
      --connectivity-type INDIRECT \
      --external-key fr-guide-hvac-02 \
      --gateways '["<gateway-instance-ocid>"]' \
      --digital-twin-adapter-id <hvac-adapter-ocid>
    
    oci iot digital-twin-instance create \
      --iot-domain-id <iot-domain-ocid> \
      --display-name FR-GUIDE-BOILER-01 \
      --connectivity-type INDIRECT \
      --external-key fr-guide-boiler-01 \
      --gateways '["<gateway-instance-ocid>"]' \
      --digital-twin-adapter-id <boiler-adapter-ocid>
    
    oci iot digital-twin-instance create \
      --iot-domain-id <iot-domain-ocid> \
      --display-name FR-GUIDE-BOILER-02 \
      --connectivity-type INDIRECT \
      --external-key fr-guide-boiler-02 \
      --gateways '["<gateway-instance-ocid>"]' \
      --digital-twin-adapter-id <boiler-adapter-ocid>

    Record the gateway device password and the IoT domain device host. To find the device host for an existing IoT domain, see Getting an IoT Domain's Details.

  • Run the CreateDigitalTwinInstance operation to create the gateway with connectivity type GATEWAY, external key fr-guide-gw-01, the gateway adapter OCID, and the authentication ID.

    Run the operation twice more to create FR-GUIDE-HVAC-01 and FR-GUIDE-HVAC-02. Set connectivity type to INDIRECT, use the matching external key, specify the HVAC adapter OCID, and include the gateway instance OCID in gateways.

    Run the operation twice more to create FR-GUIDE-BOILER-01 and FR-GUIDE-BOILER-02. Set connectivity type to INDIRECT, use the matching external key, specify the Boiler adapter OCID, and include the gateway instance OCID in gateways.

    Record the gateway device password and the IoT domain device host. To find the device host for an existing IoT domain, see Getting an IoT Domain's Details.

Topic Contract and Shared Subscriptions

External publishers use source/<device-type>/<external-key>. The Function node converts that topic to the device-host topic required by the adapters.

Public broker topicIoT device-host topic
source/gateway/fr-guide-gw-01data
source/hvacs/fr-guide-hvac-01hvacs/fr-guide-hvac-01
source/hvacs/fr-guide-hvac-02hvacs/fr-guide-hvac-02
source/boilers/fr-guide-boiler-01boilers/fr-guide-boiler-01
source/boilers/fr-guide-boiler-02boilers/fr-guide-boiler-02

For one Flow Runtime, subscribe to source/+/+. To distribute messages between two Flow Runtimes, subscribe both runtimes to $share/fr-guide/source/+/+, use MQTT 5.0, and give each runtime a different client ID, such as fr-guide-fr1 and fr-guide-fr2. Publishers continue to publish to the ordinary source/... topics.

Common Console Validation

After publishing a message, use the message timestamp to verify the target digital twin instance in the OCI Console.

  • Confirm that the gateway, HVAC, and Boiler digital twin instances are active.
  • Confirm that the raw or ingested data view contains the new gateway or indirectly connected device message.
  • Confirm that the gateway snapshot includes cpuUtilization, memoryUtilization, storageUtilization, and firmwareVersion.
  • Confirm that each HVAC snapshot includes temperature, humidity, pressure, and mode.
  • Confirm that each Boiler snapshot includes temperature and pressure.
  • Confirm that four normalized and historical values are created for each gateway and HVAC example message, and two normalized values are created for each Boiler example message.

Troubleshooting

  • If an instance creation request is rejected, confirm that the gateway uses an authentication ID and the adapter with gateway target mapping. Confirm that each indirectly connected HVAC or Boiler instance has no authentication ID, uses its device-specific adapter without gateway target mapping, and lists the active gateway.
  • If an HVAC or Boiler message is assigned to the wrong instance, confirm that the topic external key exactly matches an active instance of that device type associated with the gateway.
  • If no normalized values appear, confirm that the model content paths match the adapter payload mappings and that the incoming timestamp and numeric values match the sample format.
  • If a Flow Runtime can't reach an external broker or the IoT device host, confirm the subnet route, NAT gateway or approved egress path, NSG rules, TLS, and outbound TCP port 8883.
  • If an OCI node reports an authorization error in a later scenario, confirm that the Flow Runtime matches the dynamic group and that the resource principal policy grants access to the exact Object Storage bucket, Notifications topic, or digital twin command operation.

For general recovery steps, see Troubleshooting IoT Flow Runtimes.

FAQs

Why do I create the gateway before the HVAC and Boiler instances?
An indirectly connected digital twin instance must reference at least one active gateway when it is created.
Why does the gateway use a different adapter?
The gateway adapter contains target mapping that delegates forwarded messages to the matching HVAC or Boiler instance. The HVAC and Boiler adapters map the delegated device payloads and don't contain gateway target mapping.
Do I repeat this setup for every Flow Runtime scenario?
No. Create the shared models, adapters, gateway, HVAC instances, and Boiler instances once, and reuse them in the live data ingestion, batch data ingestion, and monitoring scenarios.
Can I use my own resource names and external keys?
Yes. Replace every matching topic, external key, flow value, and OCID consistently across the setup and the individual scenario.