Starting Workflows

Overview

This guide covers how to initiate utility measurement workflows in your application. All workflows are started through the CloneablePlatform instance and return results asynchronously.

Prerequisites

Before starting any workflow, ensure:

  1. Authentication: User is authenticated with the platform

  2. Permissions: Camera, location, and motion permissions are granted

  3. UI Wrapper: Content is wrapped in CloneableWorkflowWrapper

  4. Platform Ready: CloneablePlatform is fully initialized

Basic Setup

SwiftUI Integration

import SwiftUI
import CloneablePlatformiOS

struct UtilityMeasurementView: View {
    @EnvironmentObject var cloneable: CloneablePlatform
    @State private var isWorkflowActive = false
    
    var body: some View {
        // Essential: Wrap your content in CloneableWorkflowWrapper
        CloneableWorkflowWrapper(cloneablePlatform: cloneable) {
            VStack(spacing: 20) {
                // Your UI content here
                utilityWorkflowButtons
            }
        }
    }
    
    private var utilityWorkflowButtons: some View {
        VStack(spacing: 16) {
            Button("Measure Pole") {
                Task { await startPoleMeasurement() }
            }
            .disabled(isWorkflowActive)
            
            Button("Measure Midspan") {
                Task { await startMidspanMeasurement() }
            }
            .disabled(isWorkflowActive)
            
            Button("Measure Guy Wire") {
                Task { await startGuyMeasurement() }
            }
            .disabled(isWorkflowActive)
        }
    }
}

Pole/Vertical Measurements

Basic Pole Measurement

func startPoleMeasurement() async {
    do {
        isWorkflowActive = true
        
        // Create basic configuration
        let config = VerticalMeasurementConfiguration(
            type: .pole,
            accuracy: .standardAccuracy,
            inventoryClasses: nil,
            wireClasses: nil,
            guyWireOptions: nil,
            ownerOptions: nil,
            shouldCaptureAttachments: true
        )
        
        // Start the workflow
        let result = try await cloneable.startVerticalMeasurement(config: config)
        
        // Process the result
        await processPoleMeasurementResult(result)
        
    } catch {
        print("Pole measurement failed: \(error)")
        await handleMeasurementError(error)
    } finally {
        isWorkflowActive = false
    }
}

High-Accuracy Pole Measurement

func startHighAccuracyPoleMeasurement() async {
    do {
        let config = VerticalMeasurementConfiguration(
            type: .pole,
            accuracy: .highAccuracy,  // Requires reference stick measurement
            inventoryClasses: customInventoryClasses,
            wireClasses: customWireClasses,
            guyWireOptions: customGuyOptions,
            ownerOptions: utilityOwners,
            shouldCaptureAttachments: true
        )
        
        let result = try await cloneable.startVerticalMeasurement(config: config)
        await processHighAccuracyResult(result)
        
    } catch VerticalMeasurementError.referenceStickRequired {
        // Handle case where high accuracy requires reference stick
        await showReferenceStickInstructions()
    } catch {
        await handleMeasurementError(error)
    }
}

Pole Measurement with Custom Inventory

func startCustomPoleMeasurement() async {
    // Define custom inventory for your utility
    let customInventory = [
        InventoryClass(name: "Transformer", subcategories: [
            InventorySubcategory(name: "KVA Rating", options: ["25", "50", "75", "100"], required: true),
            InventorySubcategory(name: "Type", options: ["Overhead", "Padmount"], required: true)
        ]),
        InventoryClass(name: "Switch", subcategories: [
            InventorySubcategory(name: "Operation", options: ["Manual", "Automatic"], required: false)
        ])
    ]
    
    let config = VerticalMeasurementConfiguration(
        type: .pole,
        accuracy: .standardAccuracy,
        inventoryClasses: customInventory,
        wireClasses: nil,
        guyWireOptions: nil,
        ownerOptions: ["City Power", "Regional Coop"],
        shouldCaptureAttachments: true
    )
    
    do {
        let result = try await cloneable.startVerticalMeasurement(config: config)
        await processCustomPoleMeasurement(result)
    } catch {
        await handleMeasurementError(error)
    }
}

Midspan Measurements

Basic Midspan Measurement

func startMidspanMeasurement() async {
    do {
        let config = VerticalMeasurementConfiguration(
            type: .midspan,
            accuracy: .standardAccuracy,
            inventoryClasses: nil,              // Midspans typically don't have attachments
            wireClasses: conductorTypes,        // Focus on conductor classification
            guyWireOptions: nil,
            ownerOptions: circuitOwners,
            shouldCaptureAttachments: false     // Skip attachment documentation
        )
        
        let result = try await cloneable.startVerticalMeasurement(config: config)
        await processMidspanResult(result)
        
    } catch {
        print("Midspan measurement failed: \(error)")
        await handleMeasurementError(error)
    }
}

High-Accuracy Midspan with Conductor Types

func startHighAccuracyMidspan() async {
    let conductorTypes = [
        InventoryClass(name: "Primary Conductor", subcategories: [
            InventorySubcategory(name: "Type", options: ["ACSR", "AAC", "AAAC"], required: true),
            InventorySubcategory(name: "Size", options: ["2/0", "4/0", "336", "477"], required: true),
            InventorySubcategory(name: "Voltage", options: ["12kV", "25kV", "35kV"], required: true)
        ])
    ]
    
    let config = VerticalMeasurementConfiguration(
        type: .midspan,
        accuracy: .highAccuracy,
        inventoryClasses: nil,
        wireClasses: conductorTypes,
        guyWireOptions: nil,
        ownerOptions: ["Primary Utility", "Secondary Utility"],
        shouldCaptureAttachments: false
    )
    
    do {
        let result = try await cloneable.startVerticalMeasurement(config: config)
        await processDetailedMidspanResult(result)
    } catch {
        await handleMeasurementError(error)
    }
}

Guy Anchor Measurements

Basic Guy Wire Measurement

func startGuyMeasurement() async {
    do {
        // Guy wire measurements use a simplified workflow
        let result = try await cloneable.startGuyWorkflow()
        await processGuyMeasurementResult(result)
        
    } catch {
        print("Guy wire measurement failed: \(error)")
        await handleMeasurementError(error)
    }
}

Guy Anchor Measurement with Location Context

func startGuyMeasurementWithContext() async {
    // Ensure pole location is available for guy anchor calculations
    guard let poleLocation = getCurrentPoleLocation() else {
        await showLocationRequiredAlert()
        return
    }
    
    do {
        let result = try await cloneable.startGuyWorkflow()
        
        // Calculate anchor location using pole location and guy measurements
        let anchorLocation = calculateAnchorLocation(
            poleLocation: poleLocation,
            guyVector: result
        )
        
        await processGuyWithLocation(result, anchorLocation: anchorLocation)
        
    } catch {
        await handleMeasurementError(error)
    }
}

Workflow State Management

Managing Active Workflows

class WorkflowManager: ObservableObject {
    @Published var isWorkflowActive = false
    @Published var currentWorkflowType: WorkflowType?
    
    enum WorkflowType {
        case pole
        case midspan
        case guy
    }
    
    func startWorkflow(_ type: WorkflowType, with cloneable: CloneablePlatform) async {
        guard !isWorkflowActive else {
            print("Workflow already active")
            return
        }
        
        DispatchQueue.main.async {
            self.isWorkflowActive = true
            self.currentWorkflowType = type
        }
        
        defer {
            DispatchQueue.main.async {
                self.isWorkflowActive = false
                self.currentWorkflowType = nil
            }
        }
        
        switch type {
        case .pole:
            await startPoleMeasurement(with: cloneable)
        case .midspan:
            await startMidspanMeasurement(with: cloneable)
        case .guy:
            await startGuyMeasurement(with: cloneable)
        }
    }
}

Result Processing Examples

Basic Result Processing

func processPoleMeasurementResult(_ result: CloneableJSON) async {
    // Extract basic measurements
    if let poleInfo = result["pole_information"],
       let height = poleInfo["height"]?.getNumberValue() {
        print("Measured pole height: \(height) feet")
    }
    
    // Extract location
    if let location = result["pole_information"]?["location"]?.getLocationValue() {
        print("Pole location: \(location.coordinate)")
    }
    
    // Save complete result
    await saveResultToDatabase(result)
    
    // Show success message
    await showMeasurementComplete()
}

func processGuyMeasurementResult(_ result: GuyAnchorVector) async {
    print("Guy wire measured:")
    print("  Lead length: \(result.leadLength) feet")
    print("  Angle: \(result.angle)Β° from north")
    
    // Save guy data
    await saveGuyDataToDatabase(result)
    
    // Show completion
    await showGuyMeasurementComplete()
}

Last updated