Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.sensorup.com/llms.txt

Use this file to discover all available pages before exploring further.

Connected Asset Management Guide

The Connected Asset Management (CAM) API provides comprehensive asset management capabilities for connected operations through the su-cam-assets subgraph. CAM handles asset types, asset properties, asset hierarchy, and geospatial operations.

Overview

CAM enables you to:
  • Define and manage asset types with custom property schemas
  • Create and organize assets with hierarchical relationships
  • Query assets by type, location, and properties
  • Perform batch operations for large-scale asset management
  • Track asset states and status changes
  • Manage geospatial data and relationships

Core Concepts

Asset Types

Asset types define the schema and structure for assets. Each asset type specifies:
  • Properties: Custom attributes and their data types
  • Hierarchy: Parent-child relationships between assets
  • Extensions: External data source integrations
  • Status tracking: Asset state management configuration

Assets

Assets are instances of asset types representing physical or logical entities in your connected operations:
  • Sites: Top-level geographic locations
  • Equipment: Major operational assets
  • Components: Sub-components within equipment
  • Wells: Oil and gas well assets
  • Pipelines: Pipeline infrastructure
  • Unattributed: Assets not yet assigned to a specific type

Asset Hierarchy

Assets can be organized in parent-child relationships, enabling:
  • Multi-level organizational structures
  • Inherited properties and configurations
  • Hierarchical queries and filtering
  • Geographic nesting (e.g., equipment within sites)

Querying Assets

Get All Asset Types

query GetAssetTypes {
  assetTypes {
    all(first: 20) {
      edges {
        node {
          assetTypeId
          name
          description
          properties {
            id
            name
            dataType
            required
          }
        }
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
}

Get Specific Asset Type

query GetAssetType($assetTypeId: ID!) {
  assetTypes {
    byId(assetTypeId: $assetTypeId) {
      assetTypeId
      name
      description
      properties {
        id
        name
        dataType
        required
        defaultValue
      }
      extensions {
        id
        name
        connectionDetails {
          ... on AssetTypeExtensionConnectionSimple {
            idProperty
            idColumn
            stateProperty
          }
        }
      }
    }
  }
}
Variables:
{
  "assetTypeId": "site"
}

Query Assets by Type

query GetAssetsByType($assetTypeId: ID!) {
  camAssets(assetTypeId: $assetTypeId) {
    all(first: 20) {
      edges {
        node {
          id
          name
          description
          assetTypeId
          active
          geometry {
            type
            coordinates
          }
          properties
          parent {
            id
            name
          }
          children {
            id
            name
            assetTypeId
          }
        }
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
}
Variables:
{
  "assetTypeId": "equipment"
}

Query Asset by ID

query GetAsset($id: ID!) {
  camAssets {
    byId(id: $id) {
      id
      name
      description
      assetTypeId
      active
      geometry {
        type
        coordinates
      }
      properties
      parent {
        id
        name
        assetTypeId
      }
      status {
        statusId
        label
        setAt
        setBy
      }
    }
  }
}
Variables:
{
  "id": "site-001"
}

Filter and Search Assets

query SearchAssets($assetTypeId: ID!, $searchText: String!) {
  camAssets(assetTypeId: $assetTypeId) {
    all(
      first: 20
      fullTextSearch: { text: $searchText }
      filter: { active: true }
    ) {
      edges {
        node {
          id
          name
          description
          assetTypeId
        }
      }
      totalCount
    }
  }
}
Variables:
{
  "assetTypeId": "site",
  "searchText": "compressor"
}

Creating and Updating Assets

Create an Asset

mutation CreateAsset($input: CreateAssetInput!) {
  createAsset(input: $input) {
    asset {
      id
      name
      assetTypeId
      properties
    }
    correlationId
    errors {
      message
      type
    }
  }
}
Variables:
{
  "input": {
    "assetId": "site-abc",
    "name": "Compressor Station ABC",
    "description": "Primary compression facility",
    "assetTypeId": "site",
    "active": true,
    "group": "your-tenant-id",
    "geometry": {
      "type": "Point",
      "coordinates": [-114.0719, 51.0447]
    },
    "propertyValues": [
      {
        "propertyId": "operator",
        "value": "ACME Energy"
      },
      {
        "propertyId": "capacity",
        "value": "5000"
      }
    ]
  }
}

Update Asset Properties

mutation UpdateAssetProperty($input: UpdateAssetPropertyInput!) {
  updateAssetProperty(input: $input) {
    asset {
      id
      properties
    }
    correlationId
    errors {
      message
      type
    }
  }
}
Variables:
{
  "input": {
    "assetId": "site-abc",
    "group": "your-tenant-id",
    "propertyValues": [
      {
        "propertyId": "capacity",
        "value": "6000"
      }
    ]
  }
}

Update Asset Geometry

mutation UpdateAssetGeometry($input: UpdateAssetGeometryInput!) {
  updateAssetGeometry(input: $input) {
    asset {
      id
      geometry {
        type
        coordinates
      }
    }
    correlationId
    errors {
      message
      type
    }
  }
}
Variables:
{
  "input": {
    "assetId": "site-abc",
    "group": "your-tenant-id",
    "geometry": {
      "type": "Polygon",
      "coordinates": [[
        [-114.073, 51.045],
        [-114.071, 51.045],
        [-114.071, 51.044],
        [-114.073, 51.044],
        [-114.073, 51.045]
      ]]
    }
  }
}

Create Asset Status Record

mutation CreateAssetStatus($input: CreateAssetStatusInput!) {
  createAssetStatus(input: $input) {
    assetStatus {
      assetId
      statusId
      label
      setAt
      setBy
    }
    correlationId
    errors {
      message
      type
    }
  }
}
Variables:
{
  "input": {
    "assetId": "equipment-001",
    "group": "your-tenant-id",
    "statusId": "operational",
    "label": "Fully Operational",
    "notes": "Post-maintenance verification complete"
  }
}

Batch Operations

For large-scale asset creation or updates, CAM provides batch upsert capabilities.

Generate Batch Upload URL

query GenerateUploadUrl($input: GenerateBatchUpsertUploadUrlInput!) {
  generateBatchUpsertUploadUrl(input: $input) {
    uploadUrl
    batchUpsertReference
    expiresAt
  }
}
Variables:
{
  "input": {
    "assetTypeId": "equipment",
    "fileFormat": "CSV",
    "fileName": "equipment_batch_update.csv",
    "fileSizeBytes": 2048000,
    "group": "your-tenant-id",
    "expirationMinutes": 60
  }
}

Upload File and Trigger Batch Upsert

// 1. Get the upload URL
const { data } = await client.query({
  query: GENERATE_UPLOAD_URL,
  variables: { input: uploadParams }
})

// 2. Upload file to S3
await fetch(data.generateBatchUpsertUploadUrl.uploadUrl, {
  method: 'PUT',
  headers: { 'Content-Type': 'text/csv' },
  body: csvFileContent
})

// 3. Trigger batch processing
await client.mutate({
  mutation: gql`
    mutation BatchUpsert($ref: String!) {
      manageCamAssets(dryRun: false) {
        batchUpsert(batchUpsertReference: $ref) {
          success
          processedCount
          errors {
            row
            message
          }
        }
      }
    }
  `,
  variables: {
    ref: data.generateBatchUpsertUploadUrl.batchUpsertReference
  }
})

Asset Hierarchy Operations

Query Asset Hierarchy

query GetAssetHierarchy($rootId: ID!) {
  camAssets {
    byId(id: $rootId) {
      id
      name
      assetTypeId
      children {
        id
        name
        assetTypeId
        children {
          id
          name
          assetTypeId
        }
      }
    }
  }
}

Create Child Asset

mutation CreateChildAsset($input: CreateAssetInput!) {
  createAsset(input: $input) {
    asset {
      id
      name
      parent {
        id
        name
      }
    }
    correlationId
    errors {
      message
      type
    }
  }
}
Variables:
{
  "input": {
    "assetId": "compressor-001",
    "name": "Compressor Unit 1",
    "assetTypeId": "equipment",
    "active": true,
    "group": "your-tenant-id",
    "parent": {
      "assetId": "site-abc",
      "assetTypeId": "site"
    },
    "geometry": {
      "type": "Point",
      "coordinates": [-114.0720, 51.0448]
    }
  }
}

Geospatial Queries

CAM supports full GeoJSON geometry types for asset locations:

Query Assets by Bounding Box

query GetAssetsInBounds(
  $assetTypeId: ID!
  $minLon: Float!
  $minLat: Float!
  $maxLon: Float!
  $maxLat: Float!
) {
  camAssets(assetTypeId: $assetTypeId) {
    all(
      first: 100
      filter: {
        geometry: {
          bbox: [$minLon, $minLat, $maxLon, $maxLat]
        }
      }
    ) {
      edges {
        node {
          id
          name
          geometry {
            type
            coordinates
            bbox
          }
        }
      }
    }
  }
}

Supported Geometry Types

CAM supports all GeoJSON geometry types:
  • Point: Single location [-114.0719, 51.0447]
  • LineString: Linear features (pipelines, roads)
  • Polygon: Areas and boundaries
  • MultiPoint, MultiLineString, MultiPolygon: Collections
  • GeometryCollection: Mixed geometry types

Asset References

Query lightweight asset references for dropdowns and lookups:
query GetAssetReferences {
  camAssetReferences {
    all(first: 100) {
      edges {
        node {
          id
          name
          assetTypeId
        }
      }
    }
  }
}

CAM Engine and Datasets

Query available datasets and engine configuration:
query GetCamEngine {
  camEngine {
    datasets {
      id
      name
      assetTypeId
      sourceType
    }
  }
}

Get Datasets for Tenant

query GetCamDatasets($group: ID!) {
  camAssetsDatasets(group: $group) {
    dataset
    displayName
    assetTypeId
  }
}

Asset Configuration

Manage tenant-specific asset configurations:
query GetAssetConfigs($group: ID!) {
  assetConfigs(group: $group) {
    all {
      id
      value
    }
  }
}

Set Configuration

mutation SetAssetConfig($group: ID!, $id: ID!, $value: JSONObject!) {
  setAssetConfig(group: $group, id: $id, value: $value) {
    config {
      id
      value
    }
    correlationId
    errors {
      message
      type
    }
  }
}

Best Practices

1. Use Asset Type Filtering

Always filter by assetTypeId when querying assets to improve performance:
# Good - filtered by type
camAssets(assetTypeId: "equipment") { all(first: 20) { ... } }

# Less efficient - all asset types
camAssets { all(first: 20) { ... } }

2. Batch Operations for Scale

For bulk operations (>100 assets), use batch upsert instead of individual mutations:
# Good for >100 assets
generateBatchUpsertUploadUrlupload CSVmanageCamAssets.batchUpsert

# Use individual mutations for <100 assets
createAsset, updateAsset

3. Request Only Needed Fields

Minimize query size by selecting only required fields:
# Good - specific fields
camAssets { byId(id: "x") { id name } }

# Avoid - requesting all properties
camAssets { byId(id: "x") { id name properties ... } }

4. Use Asset References for Lookups

For dropdowns and selection lists, use camAssetReferences instead of full camAssets:
# Good - lightweight references
camAssetReferences { all { edges { node { id name } } } }

# Avoid - full asset queries for simple lookups
camAssets { all { edges { node { id name ... } } } }

5. Leverage Asset Hierarchy

Use parent-child relationships instead of flat structures:
# Good - hierarchical query
camAssets {
  byId(id: "site-001") {
    children { # Equipment at site
      children { # Components on equipment
        id
        name
      }
    }
  }
}

Error Handling

CAM mutations return errors in the standard format:
{
  "data": {
    "createAsset": {
      "asset": null,
      "correlationId": "abc-123",
      "errors": [
        {
          "message": "Asset with ID 'site-abc' already exists",
          "type": "DUPLICATE_ID"
        }
      ]
    }
  }
}
Common error types:
  • DUPLICATE_ID: Asset ID already exists
  • INVALID_PARENT: Parent asset not found or invalid type
  • INVALID_PROPERTY: Property validation failed
  • INVALID_GEOMETRY: GeoJSON geometry is malformed
  • MISSING_REQUIRED: Required field not provided