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:
Authentication: User is authenticated with the platform
Permissions: Camera, location, and motion permissions are granted
UI Wrapper: Content is wrapped in
CloneableWorkflowWrapper
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