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 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.
Tasks
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. |
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.
| Resource | Example value |
|---|---|
| Domain group | FR-GUIDE-DG |
| IoT domain | fr-guide-domain |
| Gateway display name | FR-GUIDE-GW-01 |
| Gateway external key | fr-guide-gw-01 |
| HVAC display names | FR-GUIDE-HVAC-01 and FR-GUIDE-HVAC-02 |
| HVAC external keys | fr-guide-hvac-01 and fr-guide-hvac-02 |
| Boiler display names | FR-GUIDE-BOILER-01 and FR-GUIDE-BOILER-02 |
| Boiler external keys | fr-guide-boiler-01 and fr-guide-boiler-02 |
| Public MQTT broker | test.mosquitto.org |
| Public MQTT TLS port | 8883 |
| Single-runtime topic | source/+/+ |
| 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:
| Field | Value |
|---|---|
| Name | fr-guide-public-broker |
| Host | test.mosquitto.org |
| Port | 8883 |
| SSL/TLS | Enabled |
| Protocol | MQTT 5.0 |
| Username and password | Leave blank |
Placeholder Values
Description of the placeholder values in this example.
| Placeholder | Description |
|---|---|
<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.
{
"@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"}
]
}{
"@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"}
]
}{
"@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.
- 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.
- Select Digital twin models, and then select Create.
- Enter a name for the gateway model, upload
gateway-model.jsonor paste its specification, and then select Create. - Repeat the preceding steps for
hvac-model.jsonandboiler-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.jsonRun the CreateDigitalTwinModel operation for
gateway-model.json,hvac-model.json, andboiler-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.
{
"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": "$"
}
}[
{
"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"
}
}
]{
"referenceEndpoint": "/data",
"referencePayload": {
"dataFormat": "JSON",
"data": {
"time": 1773768299143534,
"temperature": 72,
"humidity": 45,
"pressure": 101.2,
"mode": "cool"
}
},
"envelopeMapping": {
"timeObserved": "$.time"
}
}[
{
"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"
}
}
]{
"referenceEndpoint": "/telemetry",
"referencePayload": {
"dataFormat": "JSON",
"data": {
"timestamp": 1773768299143534,
"temperature": 0,
"pressure": 0
}
},
"envelopeMapping": {
"timeObserved": "$.timestamp"
}
}[
{
"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.
- On the IoT domain details page, select Digital twin adapters, and then select Create.
- Enter a name for the gateway adapter and select the gateway model.
- Upload or paste
gateway-envelope.jsonas the inbound envelope andgateway-routes.jsonas the inbound routes, and then select Create. - Create the HVAC adapter by selecting the HVAC model and using
hvac-envelope.jsonandhvac-routes.json. - Create the Boiler adapter by selecting the Boiler model and using
boiler-envelope.jsonandboiler-routes.json. - 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.jsonRecord 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.
- On the IoT domain details page, select Digital twin instances, and then select Create.
- Create the gateway with display name
FR-GUIDE-GW-01, external keyfr-guide-gw-01, connectivity type Gateway, the gateway adapter, and a device authentication ID. - Record the gateway digital twin instance OCID and device password.
- Create an indirectly connected instance with display name
FR-GUIDE-HVAC-01and external keyfr-guide-hvac-01. - Select the HVAC adapter and associate the digital twin instance with the gateway.
- Repeat the preceding step for
FR-GUIDE-HVAC-02and external keyfr-guide-hvac-02. - Create an indirectly connected instance with display name
FR-GUIDE-BOILER-01and external keyfr-guide-boiler-01. Select the Boiler adapter and associate the instance with the gateway. - Repeat the preceding step for
FR-GUIDE-BOILER-02and external keyfr-guide-boiler-02. - 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 keyfr-guide-gw-01, the gateway adapter OCID, and the authentication ID.Run the operation twice more to create
FR-GUIDE-HVAC-01andFR-GUIDE-HVAC-02. Set connectivity type toINDIRECT, use the matching external key, specify the HVAC adapter OCID, and include the gateway instance OCID ingateways.Run the operation twice more to create
FR-GUIDE-BOILER-01andFR-GUIDE-BOILER-02. Set connectivity type toINDIRECT, use the matching external key, specify the Boiler adapter OCID, and include the gateway instance OCID ingateways.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 topic | IoT device-host topic |
|---|---|
source/gateway/fr-guide-gw-01 | data |
source/hvacs/fr-guide-hvac-01 | hvacs/fr-guide-hvac-01 |
source/hvacs/fr-guide-hvac-02 | hvacs/fr-guide-hvac-02 |
source/boilers/fr-guide-boiler-01 | boilers/fr-guide-boiler-01 |
source/boilers/fr-guide-boiler-02 | boilers/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, andfirmwareVersion. - Confirm that each HVAC snapshot includes
temperature,humidity,pressure, andmode. - Confirm that each Boiler snapshot includes
temperatureandpressure. - 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.
Related Scenarios
Use the IoT resources created in this scenario to complete any of these scenarios.