Skip to content

Commit 81cceb2

Browse files
committed
added samples of models, routes and other support info
1 parent c05cdc2 commit 81cceb2

14 files changed

+258
-61
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
you must have setup the IoT instance
2+
You must have completed the instructions for Srep 1 (setting upt he VCN) at https://docs.oracle.com/en-us/iaas/Content/internet-of-things/connect-analytics-cloud.htm
3+
The first part of these steps is the same for Analytics AND Direct DB access from a compute instance
4+
5+
export IOT_DB_ACCESS_VCN_OCID=<your vcn's ocid>
6+
7+
# $IOT_DOMAIN_GROUP_OCID is set when you follow the process in instructions.txt
8+
# connect the domain group to the vcn, wait for it to complete
9+
oci iot domain-group configure-data-access --db-allow-listed-vcn-ids "[\"$IOT_DB_ACCESS_VCN_OCID\"]" --iot-domain-group-id $IOT_DOMAIN_GROUP_OCID --wait-for-state SUCCEEDED --wait-for-state FAILED
10+
11+
## The following are the the compute oinstance instructions
12+
Basically go on from step 3 at https://docs.oracle.com/en-us/iaas/Content/internet-of-things/connect-database.htm
13+
14+
15+
16+
## The following are the anlytics instructions
17+
18+
export IOT_DOMAIN_GROUP_INFO=`oci iot domain-group get --iot-domain-group-id $IOT_DOMAIN_GROUP_OCID`
19+
export IOT_DB_CONNECTION_STRING=`echo $IOT_DOMAIN_GROUP_INFO | jq -r '.data."db-connection-string"'`
20+
export IOT_DB_TOKEN_SCOPE=`echo $IOT_DOMAIN_GROUP_INFO | jq -r '.data."db-token-scope"'`
21+
22+
# get the tenancy OCID
23+
# set the idcs name and the idcs group name you're using, use Default if you're using the system wide idcs
24+
export IDCS_DOMAIN_NAME=<the name of your IDCS instance, e.g. iotdomain or Default>
25+
export IDCS_IOT_GROUP_NAME=<the name of the IDCS group you created, this could be the same one you used for ORDS if you've set that up>
26+
export OCI_TENANCY_OCID=`oci iam compartment list --query 'data[?contains("compartment-id", \`.tenancy\`)]."compartment-id" | [0]' --raw-output`
27+
28+
export OCI_TENANCY_OCID=`oci iam compartment list --query 'data[?contains("compartment-id", \`.tenancy\`)]."compartment-id" | [0]' --raw-output`
29+
30+
31+
oci iot domain configure-direct-data-access --iot-domain-id $IOT_DOMAIN_OCID --db-allow-listed-identity-group-names '["'$OCI_TENANCY_OCID':'$IDCS_DOMAIN_NAME'/'$IDCS_IOT_GROUP_NAME'", "'$OCI_TENANCY_OCID':OracleIdentityCloudService/Domain_Specialists"]' --wait-for-state SUCCEEDED --wait-for-state FAILED
32+
33+
34+
# make sure it worked, look in the domain details
35+
oci iot domain get --iot-domain-id $IOT_DOMAIN_OCID | jq -r '.data."db-allow-listed-identity-group-names"'
36+
37+
you shouold see some contents in the resulting array
38+
39+
follow the instructions in step 6 at https://docs.oracle.com/en-us/iaas/Content/internet-of-things/connect-analytics-cloud.htm to create and setup the Analytics instance and connect it
40+
41+
## The following are the
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# this will delete the twin instance, model and adaptor
2+
3+
oci iot digital-twin-instance delete --digital-twin-instance-id $DIGITAL_TWIN_INSTANCE_OCID --force --wait-for-state DELETED
4+
oci iot digital-twin-adapter delete --digital-twin-adapter-id $DIGITAL_TWIN_ADAPTER_OCID --force --wait-for-state DELETED
5+
oci iot digital-twin-model delete --digital-twin-model-id $DIGTAL_TWIN_MODEL_ID --force --wait-for-state DELETED
6+
7+
unset DIGTAL_TWIN_MODEL_ID
8+
unset DIGITAL_TWIN_ADAPTER_OCID
9+
unset DIGITAL_TWIN_INSTANCE_OCID
10+
unset DEVICE_EXTERNAL_KEY

IoTSonnenUploader/DigitalTwin/HomeBatteryDTMI.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,17 @@
123123
"schema": "integer",
124124
"unit": "watt"
125125
},
126+
{
127+
"@type": [
128+
"Telemetry",
129+
"Historized",
130+
"EnergyRate"
131+
],
132+
"displayName": "Inverter power intake",
133+
"name": "InverterPowerWattsPointInTime",
134+
"schema": "integer",
135+
"unit": "watt"
136+
},
126137
{
127138
"@type": [
128139
"Telemetry",

IoTSonnenUploader/DigitalTwin/Instructions.txt

Lines changed: 48 additions & 53 deletions
Large diffs are not rendered by default.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
setup ORDS data access as described in the documentation at https://docs.oracle.com/en-us/iaas/Content/internet-of-things/connect-iot-ords.htm
2+
3+
# get the various system values from the setup and use them here
4+
# sub steps are from "Step 1: Create a Confidential Application for your Identity Domain"
5+
# in the URL above.
6+
# note that for the IOT_ORDS_IDSC_PASSWORD you may need to create a non admin user and set a password for them as well as assigning them to your group if creating your own domain as an admin (rather than using a user in an existing one)
7+
# If using the administrator user you created for tyhe domain then under the domain users tab select tt user then in the actions dropdown for users chose reset password and a password email will be sent
8+
# unclear if the user name and password relate to the new identify domain or the main once for the tenancy
9+
10+
export IOT_ORDS_IDCS_USERNAME=<email address or other id used for the user in the identity domain e.g. [email protected] or iotuser for a local user>
11+
export IOT_ORDS_IDCS_PASSWORD=<password set in the IDCS for the user>
12+
export IOT_ORDS_OAUTH_ID=<Client id from OAUTH Integrated application config page - shown at step 18/19>
13+
export IOT_ORDS_OAUTH_SECRET=<Client secret from OAUTH Integrated application config page - shown at step 18/19>
14+
export IOT_IDENTITY_DOMAIN_HOST=<From the identity details at step 31>
15+
16+
# this uses the above to get the token and so on
17+
export IOT_IDENTITY_DOMAIN_HOST_SHORT=`echo $IOT_IDENTITY_DOMAIN_HOST | tr '.' ' ' | awk '{print $1}'`
18+
export IOT_IDENTITY_DOMAIN_URL=https://$IOT_IDENTITY_DOMAIN_HOST:443/oauth2/v1/token
19+
# the IOT_DOMAIN_GROUP_SHORT_ID and IOT_DOMAIN_SHORT_ID were set in the Instructions.txt
20+
export IOT_ORDS_AUTH_DETAILS=`curl -s --request POST --url "${IOT_IDENTITY_DOMAIN_URL}" --header 'Content-Type: application/x-www-form-urlencoded' --user "${IOT_ORDS_OAUTH_ID}:${IOT_ORDS_OAUTH_SECRET}" --data "scope=/${IOT_DOMAIN_GROUP_SHORT_ID}/iot/${IOT_DOMAIN_SHORT_ID}" --data "grant_type=password" --data "username=${IOT_ORDS_IDCS_USERNAME}" --data "password=${IOT_ORDS_IDCS_PASSWORD}"`
21+
export IOT_ORDS_AUTH_ACCESS_TOKEN=`echo $IOT_ORDS_AUTH_DETAILS | jq -r '.access_token'`
22+
export IOT_ORDS_AUTH_TOKEN_DURATION=`echo $IOT_ORDS_AUTH_DETAILS | jq -r '.expires_in'`
23+
export IOT_ORDS_AUTH_TOKEN_TYPE=`echo $IOT_ORDS_AUTH_DETAILS | jq -r '.token_type'`
24+
25+
# lets get a couple of data objects
26+
# this will get a couple of the raw data irtems (limiting it to 2)
27+
curl -k -s --get --location "https://${IOT_DOMAIN_GROUP_DATA_HOST}/ords/$IOT_DOMAIN_SHORT_ID/20250531/rawData" --header "Authorization: Bearer ${IOT_ORDS_AUTH_ACCESS_TOKEN}" --header "Content-Type: application/json" --data-urlencode offset=0 --data-urlencode limit=2 | jq '.items'
28+
# we can put a query in place - let's limit it to raw data for the specific digital twin
29+
curl -k -s --get --location "https://${IOT_DOMAIN_GROUP_DATA_HOST}/ords/$IOT_DOMAIN_SHORT_ID/20250531/rawData" --header "Authorization: Bearer ${IOT_ORDS_AUTH_ACCESS_TOKEN}" --header "Content-Type: application/json" --data-urlencode offset=0 --data-urlencode limit=2 --data-urlencode 'q={"$and":[{"digital_twin_instance_id":"'$DIGITAL_TWIN_INSTANCE_OCID'"}]}"' | jq '.items'
30+
31+
32+
# we can of course access the other data tables, this is the snapshot data, we'll retrieve the most recent 20 as each data item in the upload is in its own row
33+
curl -k -s --get --location "https://${IOT_DOMAIN_GROUP_DATA_HOST}/ords/$IOT_DOMAIN_SHORT_ID/20250531/snapshotData" --header "Authorization: Bearer ${IOT_ORDS_AUTH_ACCESS_TOKEN}" --header "Content-Type: application/json" --data-urlencode offset=0 --data-urlencode limit=20 --data-urlencode 'q={"$and":[{"digital_twin_instance_id":"'$DIGITAL_TWIN_INSTANCE_OCID'"}]}"' | jq '.items'
34+
35+
# The historized data isn't so helpfull, were just getting one content path
36+
curl -k -s --get --location "https://${IOT_DOMAIN_GROUP_DATA_HOST}/ords/$IOT_DOMAIN_SHORT_ID/20250531/historizedData" --header "Authorization: Bearer ${IOT_ORDS_AUTH_ACCESS_TOKEN}" --header "Content-Type: application/json" --data-urlencode offset=0 --data-urlencode limit=20 --data-urlencode 'q={"$and":[{"digital_twin_instance_id":"'$DIGITAL_TWIN_INSTANCE_OCID'"}]}"' | jq '.items'
37+
38+
# let's add an additional quesy item to the quest to also focus on SolarGeneration
39+
curl -k -s --get --location "https://${IOT_DOMAIN_GROUP_DATA_HOST}/ords/$IOT_DOMAIN_SHORT_ID/20250531/historizedData" --header "Authorization: Bearer ${IOT_ORDS_AUTH_ACCESS_TOKEN}" --header "Content-Type: application/json" --data-urlencode offset=0 --data-urlencode limit=20 --data-urlencode 'q={"$and":[{"digital_twin_instance_id":"'$DIGITAL_TWIN_INSTANCE_OCID'"}, {"content_path":"SolarGeneration"}]}"' | jq '.items'
40+
41+
# that was the data we wanted, but not very useful as it was some pretty random items, let's try and order it, we'll include some poer draw numbers as well
42+
curl -k -s --get --location "https://${IOT_DOMAIN_GROUP_DATA_HOST}/ords/$IOT_DOMAIN_SHORT_ID/20250531/historizedData" --header "Authorization: Bearer ${IOT_ORDS_AUTH_ACCESS_TOKEN}" --header "Content-Type: application/json" --data-urlencode offset=0 --data-urlencode limit=20 --data-urlencode 'q={"$and":[{"digital_twin_instance_id":"'$DIGITAL_TWIN_INSTANCE_OCID'"}, {"content_path":"SolarGeneration"}],"$orderby":{"time_observed":"desc"}}"' | jq '.items'
43+
44+
# of course we may want multiple data items, so let's get both thye SolarGeneration and the DischargePower - it's up to thge called to look at the returned data and decide which what resulting rows relate to which data item of course
45+
curl -k -s --get --location "https://${IOT_DOMAIN_GROUP_DATA_HOST}/ords/$IOT_DOMAIN_SHORT_ID/20250531/historizedData" --header "Authorization: Bearer ${IOT_ORDS_AUTH_ACCESS_TOKEN}" --header "Content-Type: application/json" --data-urlencode offset=0 --data-urlencode limit=20 --data-urlencode 'q={"$and":[{"digital_twin_instance_id":"'$DIGITAL_TWIN_INSTANCE_OCID'"}, {"content_path": {"$in": ["SolarGeneration", "DischargePower"]}}],"$orderby":{"time_observed":"desc"}}"' | jq '.items'
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# this follows the steps to get the various OCID's and so on.
2+
# it is basically all of the steps in the instructions.txt but
3+
# with none of the create or modify steps
4+
# Each step should work if the one before it suceeds PROVIDED
5+
# that the object at that step exists. I.e. if the adaptor has
6+
# not been created (or has been destriyed) then you probaly don't
7+
# have an instance so can't retrieve the instance OCID
8+
# note that in some cases you may need to set some environment
9+
# variables as they use things like names to work.
10+
#
11+
# Things you may need to change are here
12+
#
13+
export IOT_COMPARTMENT_OCID=<compartment ocid>
14+
export DEVICE_VAULT_SECRET_OCID=<the secret ocid>
15+
16+
# change these names as required
17+
export IOT_DOMAIN_GROUP_NAME=iot-domain-group-timg
18+
export IOT_DOMAIN_NAME=iot-domain-timg
19+
export DEVICE_ID=timssonnen
20+
# note that this is set for homebattery (the generic model), but it might well be sonnenbattery for the sonnen specific model
21+
export DIGITAL_TWIN_MODEL_NAME=homebattery
22+
# DIGITAL_TWIN_MODEL_FILE_NAME should be the name of the file containing the model for example HomeBatteryDTMI.json for the generic home battery, SonnenSpecificDTMI.json for the sonnen specific version
23+
export DIGITAL_TWIN_MODEL_FILE_NAME=HomeBatteryDTMI.json
24+
# this will be one of sonnen-direct-mapping, sonnen-single-route or sonnen-multiple-routes
25+
export DIGITAL_TWIN_ADAPTER_NAME=sonnen-multiple-routes
26+
# get the domain group info
27+
# get the domain group ocid (only run this once it has been created)
28+
export IOT_DOMAIN_GROUP_OCID=`oci iot domain-group list --display-name $IOT_DOMAIN_GROUP_NAME --compartment-id $IOT_COMPARTMENT_OCID | jq -r '.data.items[]| select (."lifecycle-state" == "ACTIVE") | ."id"'`
29+
30+
# get the data host
31+
export IOT_DOMAIN_GROUP_DATA_HOST=`oci iot domain-group get --iot-domain-group-id $IOT_DOMAIN_GROUP_OCID | jq -r '.data."data-host"'`
32+
export IOT_DOMAIN_GROUP_SHORT_ID=`echo $IOT_DOMAIN_GROUP_DATA_HOST| tr '.' ' ' | awk '{print $1}'`
33+
# Now get the domain stuff
34+
export IOT_DOMAIN_OCID=`oci iot domain list --display-name $IOT_DOMAIN_NAME --compartment-id $IOT_COMPARTMENT_OCID --iot-domain-group-id $IOT_DOMAIN_GROUP_OCID | jq -r '.data.items[]| select (."lifecycle-state" == "ACTIVE") | ."id"'`
35+
export IOT_DOMAIN_HOST=`oci iot domain get --iot-domain-id $IOT_DOMAIN_OCID | jq -r '.data."device-host"'`
36+
export IOT_DOMAIN_SHORT_ID=`echo $IOT_DOMAIN_HOST| tr '.' ' ' | awk '{print $1}'`
37+
38+
# these are only relevant if you have setup the digital twin model
39+
# the DIGITAL_TWIN_MODEL_NAME should relate to the model you are creating, e.g. homebattery for the generic model, sonnenbattery for the sonnen specific one
40+
export DIGITAL_TWIN_MODEL_ID=`oci iot digital-twin-model list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DIGITAL_TWIN_MODEL_NAME | jq -r '.data.items[]| select (."lifecycle-state" == "ACTIVE") | ."id"'`
41+
42+
# these are only relevant if you have setup a digital twin adaptor
43+
# DIGITAL_TWIN_MODEL_FILE_NAME should be the name of the file containing the model for example HomeBatteryDTMI.json for the generic home battery, SonnenSpecificDTMI.json for the sonnen specific version
44+
export DIGITAL_TWIN_MODEL_IDENTIFIER=`cat $DIGITAL_TWIN_MODEL_FILE_NAME | jq -r '.["@id"]'`
45+
export DIGITAL_TWIN_ADAPTER_OCID=`oci iot digital-twin-adapter list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DIGITAL_TWIN_ADAPTER_NAME | jq -r '.data.items[]| select (."lifecycle-state" == "ACTIVE") | ."id"'`
46+
47+
# the digital twin instance itself
48+
# this can work if there is not a model or adaptor configured
49+
# get the OCID of the digital twin
50+
export DIGITAL_TWIN_INSTANCE_OCID=`oci iot digital-twin-instance list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DEVICE_ID | jq -r '.data.items[]| select (."lifecycle-state" == "ACTIVE") | ."id"'`
51+
# and the external key
52+
export DEVICE_EXTERNAL_KEY=`oci iot digital-twin-instance get --digital-twin-instance-id $DIGITAL_TWIN_INSTANCE_OCID | jq -r '.data."external-key"'`
53+
echo Device external key $DEVICE_EXTERNAL_KEY
54+
# needed to setup the client code
55+
export DEVICE_SECRET_BASE64=`oci secrets secret-bundle get --secret-id $DEVICE_VAULT_SECRET_OCID --stage CURRENT | jq -r '.data."secret-bundle-content".content'`
56+
export DEVICE_SECRET=`echo $DEVICE_SECRET_BASE64 | base64 --decode`
57+
58+
# this is for APEX, only relevant if APEX has been setup
59+
#Get the apex URL
60+
echo APEX_URL "https://$IOT_DOMAIN_GROUP_DATA_HOST/ords/apex/"
61+
#get the user id and workspace
62+
echo APEX_Workspace "$IOT_DOMAIN_SHORT_ID"__WKSP
63+
echo APEX_User "$IOT_DOMAIN_SHORT_ID"__WKSP
64+
echo APEX_Schema "$IOT_DOMAIN_SHORT_ID"__IOT

IoTSonnenUploader/DigitalTwin/SonnenSpecificDTMI.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,17 @@
123123
"schema": "integer",
124124
"unit": "watt"
125125
},
126+
{
127+
"@type": [
128+
"Telemetry",
129+
"Historized",
130+
"EnergyRate"
131+
],
132+
"displayName": "Inverter power intake",
133+
"name": "inverterPowerWattsPointInTime",
134+
"schema": "integer",
135+
"unit": "watt"
136+
},
126137
{
127138
"@type": [
128139
"Telemetry"

IoTSonnenUploader/DigitalTwin/sonnen-to-generic-mapping-envelope.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"reservedBatteryCapacityPercentage": 0,
1414
"solarProductionWattsPointInTime": 0,
1515
"time": 123456,
16+
"inverterPowerWattsPointInTime": 42,
1617
"timestamp": "2025-11-18T16:23:52.081763412Z"
1718
},
1819
"data-format": "JSON"

IoTSonnenUploader/DigitalTwin/sonnen-to-generic-mapping-multiple-routes.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"time": 1763981430279,
1818
"timestamp": "2025-11-24T10:50:30.279369Z[Europe/London]",
1919
"batteryCharging": false,
20-
"batteryDischarging": true
20+
"batteryDischarging": true,
21+
"inverterPowerWattsPointInTime": 42
2122
}
2223
},
2324
"payload-mapping": {
@@ -31,7 +32,8 @@
3132
"$.CapacityRemaining": "$.remainingBatteryCapacityWattHours",
3233
"$.ReservedChargePercentage": "$.reservedBatteryCapacityPercentage",
3334
"$.SolarGeneration": "$.solarProductionWattsPointInTime",
34-
"$.StatusTimestamp": "$.timestamp"
35+
"$.StatusTimestamp": "$.timestamp",
36+
"$.InverterPowerWattsPointInTime": "$.inverterPowerWattsPointInTime"
3537
}
3638
},
3739
{

IoTSonnenUploader/DigitalTwin/sonnen-to-generic-mapping-single-route.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"$.CapacityRemaining": "$.remainingBatteryCapacityWattHours",
1414
"$.ReservedChargePercentage": "$.reservedBatteryCapacityPercentage",
1515
"$.SolarGeneration": "$.solarProductionWattsPointInTime",
16+
"$.InverterPowerWattsPointInTime": "$.inverterPowerWattsPointInTime",
1617
"$.StatusTimestamp": "$.timestamp"
1718
},
1819
"reference-payload": {
@@ -30,7 +31,8 @@
3031
"time": 1763981430279,
3132
"timestamp": "2025-11-24T10:50:30.279369Z[Europe/London]",
3233
"batteryCharging": false,
33-
"batteryDischarging": true
34+
"batteryDischarging": true,
35+
"inverterPowerWattsPointInTime": 42
3436
}
3537
}
3638
}

0 commit comments

Comments
 (0)