A professional WiFi analysis application for Spectrum that combines Apple's ARKit and RoomPlan technologies to create comprehensive WiFi coverage maps and professional reports. Features advanced coordinate alignment using iOS 17+ custom ARSession support for seamless room scanning and AR visualization integration.
- Room Scanning: Uses Apple RoomPlan to capture and analyze 3D room layouts
- WiFi Analysis: Real-time WiFi speed testing and signal strength measurement
- AR Visualization: Augmented reality overlay showing WiFi measurements in 3D space
- Professional Reports: Generate detailed WiFi analysis reports with floor plans
- Architectural Floor Plans: Professional-style floor plans with proper symbols
- π iOS Simulator Support: Complete UI testing with mock data (no hardware required)
- π± Universal Device Support: Graceful degradation on non-LiDAR devices with placeholder views
- Smart Room Detection: Automatically identifies room types (kitchen, bedroom, bathroom, etc.)
- Furniture Recognition: Detects and maps appliances, furniture, and fixtures
- WiFi Heatmaps: Visual representations of signal strength and coverage
- Router Placement Recommendations: Suggests optimal router locations
- Distance-Based Measurements: Records WiFi data every foot of movement
- Speed Test Progress: Visual progress indicators during network testing
- Perfect Coordinate Alignment: iOS 17+ shared ARSession for zero coordinate drift
- Seamless Mode Transitions: Instant switching between room scanning and WiFi surveying
- Enhanced Error Handling: Graceful handling of tracking failures and device positioning issues
- Real-time Guidance: Contextual user guidance for optimal camera positioning
- π³ Tactile Feedback: Scanner-like haptic patterns that respond to discovery events
- π Test Point Visualization: Visual markers showing where WiFi tests have been conducted
- ποΈ User-Controlled Completion: Only user can declare survey complete - no premature system completion
- π§ Optimized UI Layout: Buttons positioned to avoid obstructing RoomPlan 3D model
- π‘ Router & Extender Placement: Interactive AR system for optimal network device positioning
- π¬ Advanced RF Propagation: ITU indoor path loss models for accurate signal prediction
- π Multi-band WiFi 7 Support: 2.4GHz, 5GHz, and 6GHz frequency band analysis
- π― Coverage Confidence Scoring: Weighted confidence calculations for prediction accuracy
- Start Room Scan β User-controlled scanning with real-time feedback
- Seamless Mode Switch β Unified toggle between scanning and surveying
- Perfect Coordinate Alignment β iOS 17+ shared ARSession maintains spatial context
- WiFi Survey β AR-guided WiFi measurement collection with visual test point markers
- Router & Extender Placement β Interactive AR positioning for optimal network coverage
- Professional Results β Architectural-style floor plans and reports
- Demo floor plan is now explicit only. Use the "π View Floor Plan Demo" button (unsupported devices) or call
RoomCaptureViewController.showFloorPlanDemo(), which presentsFloorPlanViewControllerwithisDemoMode = trueso it loads sample data. - Real scans navigate to
FloorPlanViewControllerviaupdateWithData(heatmapData:roomAnalyzer:...). In this path, demo mode is disabled and any sample arrays are cleared so only real RoomPlan-derived data renders. - On device, if RoomPlan returns no usable geometry (world tracking failure), the app creates a minimal fallback room labeled "Unknown" to allow WiFi visualization. This is not demo data.
- Spectrum Branding: Corporate colors, fonts, and styling throughout
- Color-Coded Status: Blue (scanning), Green (complete), Orange (measuring)
- Architectural Symbols: Professional floor plan symbols matching industry standards
- Context Preservation: Room outlines remain visible in AR mode
- Main interface controller managing scanning workflow
- Handles user interactions and state transitions
- Coordinates between RoomPlan capture and WiFi analysis
- Key Features:
- User-controlled start/stop scanning
- Real-time status updates with visual feedback
- Seamless transition between scanning modes
- Tactile haptic feedback for discovery events
- Intelligent room type classification using object detection
- Enhanced algorithm with size/shape fallback logic
- Furniture and appliance cataloging
- Algorithm Features:
- Object-based scoring (refrigerator β kitchen, bed β bedroom)
- Size-based fallback (small rooms β bathroom, large β living room)
- RoomPlan Confidence Integration: Uses Apple's confidence scores for surfaces and objects
- Weighted Confidence Calculation: 40% surface + 40% furniture relevance + 20% object detection
- Real-time WiFi speed testing with progress tracking
- Distance-based measurement collection (every 1 foot)
- WiFi performance analysis and signal modeling
- Performance Features:
- Throttled measurements to prevent device overload
- Real speed testing with downloadable content
- Progress callbacks for user feedback
- Network Data Integration: Queries NetworkDataCollector for current network info
- Single source of truth for all network information
- Cellular data collection (carrier, technology, signal strength)
- WiFi network detection (SSID, BSSID, network path)
- Location services integration for coverage analysis
- Lightweight Design: Data collection only, no analysis
- Auto-Integration: Provides network info to WiFiSurveyManager automatically
- AR overlay system with performance optimizations
- Room outline preservation for spatial context
- WiFi measurement visualization with 3D nodes
- Test Point Visualization: Persistent markers showing survey coverage
- Optimization Features:
- Node pooling for memory efficiency
- Reduced AR complexity for better performance
- Limited node count (20 max) for smooth operation
- Separate test point markers (50 max) for survey guidance
- Professional architectural-style floor plan rendering with scrollable layout
- Architectural doorway visualization with proper wall gaps and orientation
- Realistic furniture and appliance symbols
- Interactive heatmap visualization with toggle controls
- Visual Features:
- Fixed scroll view layout for proper content display
- Professional doorway gaps integrated into wall structures
- Wall-aware doorway positioning with correct angles
- Clean architectural symbols matching industry standards
- Furniture symbols matching architectural standards
- Room shape accuracy using wall detection
RoomPlan Capture β Room Analysis β WiFi Survey β AR Visualization β Report Generation
β
NetworkDataCollector β β WiFiSurveyManager (Network Info Query)
β
Cellular + WiFi + Location Data β Export System
Core App (Integrated)
βββ WiFiSurveyManager (WiFi Performance)
βββ NetworkDataCollector (Network Information) β Single Source of Truth
βββ PlumePlugin (Band Steering)
βββ Export System (Unified Data Export)
WiFiMapFramework (Integrated into app)
βββ Core, RFPropagation, PlacementOptimization, RoomPlan
βββ No external Swift Package dependency
WiFiControlProviderprotocol abstracts WiFi control/steering. A NoOp provider is used by default; the Plume module can be owned by a separate team and wired as a provider implementation later without adding a hard compile-time dependency to the app target.
- When RoomPlan cannot establish robust tracking or yields zero floors/walls, the app creates a minimal square room labeled "Unknown" to continue WiFi survey visualization.
- Tips to avoid fallback:
- Ensure good lighting and scan the floor and full wall perimeter slowly.
- Allow a few seconds for AR tracking to stabilize before switching modes.
- Avoid covering the LiDAR/camera.
RoomPlanSimple/
βββ RoomCaptureViewController.swift # Main UI coordinator and state management
βββ RoomAnalyzer.swift # Room type classification and furniture detection
βββ WiFiSurveyManager.swift # WiFi performance testing and measurement collection
βββ ARVisualizationManager.swift # 3D AR rendering and test point visualization
βββ FloorPlanViewController.swift # 2D architectural floor plan rendering
βββ SpectrumBranding.swift # Corporate design system and UI components
βββ WiFiReportGenerator.swift # HTML report generation and export
βββ DataExportManager.swift # Unified data export system
Plugin Architecture/
βββ NetworkDataPlugin/
β βββ NetworkDataCollector.swift # Single source for all network information
βββ PlumePlugin/
β βββ PlumePlugin.swift # Main Plume API integration
β βββ PlumeAPIManager.swift # API connection and steering commands
β βββ PlumeSteeringOrchestrator.swift # Comprehensive testing workflows
β βββ PlumeDataCorrelator.swift # Timestamp/location correlation
β βββ PlumeSimulationEngine.swift # Testing without real hardware
Network Device Management/
βββ NetworkDeviceManager.swift # Core device placement logic and surface analysis
βββ NetworkDevice3DModels.swift # Realistic 3D device models with SceneKit
βββ AR + Floor Plan Integration # Device visualization in both 3D AR and 2D plans
Comprehensive router and WiFi extender placement system with intelligent surface detection and AR visualization. Uses RoomPlan furniture data to recommend optimal device positioning for maximum WiFi coverage.
- Tap-to-Place Interface: Interactive AR positioning with real-time 3D model preview
- User Control: Complete flexibility in router location selection
- Visual Feedback: Realistic router model with animated LED indicators and antennas
- Surface Analysis: Analyzes all detected furniture for suitability scoring
- Intelligent Scoring: Combines furniture type, height, surface area, and RoomPlan confidence
- Automatic Placement: Places extender on optimal surface after router selection
- MVP Implementation: Prioritizes any detected table for immediate functionality
- Realistic Models: Detailed SceneKit geometry with proper materials
- Router: Main body, dual antennas, LED indicators, ventilation grilles
- Extender: Compact design, power prongs, WiFi signal rings, Ethernet port
- Visual Effects: Pulsing animations, device highlighting, connection lines
- Interactive Labels: Billboard-constrained labels with emoji icons (π‘ Router, πΆ Extender)
- Device Symbols: Professional symbols with colored backgrounds
- Connection Visualization: Animated lines showing router-extender relationships
- Confidence Indicators: Visual feedback on placement confidence scores
- Architectural Integration: Clean integration with existing floor plan symbols
Central coordinator for all device placement logic:
class NetworkDeviceManager: ObservableObject {
@Published var router: NetworkDevice?
@Published var extenders: [NetworkDevice] = []
@Published var suitableSurfaces: [SuitableSurface] = []
@Published var isRouterPlacementMode: Bool = false
// Surface suitability scoring algorithm
private func calculateSuitabilityScore(for item: RoomAnalyzer.FurnitureItem) -> Float {
var score: Float = 0.0
// Base score by furniture type (tables preferred)
switch item.category {
case .table: score += 0.8
case .sofa: score += 0.4
default: score += 0.1
}
// Height optimization (waist-height ideal)
let idealHeight: Float = 1.0
let heightDifference = abs(item.position.y - idealHeight)
let heightScore = max(0, 0.2 - heightDifference * 0.1)
score += heightScore
// Surface area consideration
let surfaceArea = item.dimensions.x * item.dimensions.z
let areaScore = min(0.2, surfaceArea * 0.02)
score += areaScore
// RoomPlan confidence integration
score += item.confidence * 0.1
return min(1.0, score)
}
}Realistic 3D model creation with detailed geometry:
static func createRouterModel() -> SCNNode {
let routerNode = SCNNode()
// Main body with realistic materials
let bodyGeometry = SCNBox(width: 0.25, height: 0.05, length: 0.15, chamferRadius: 0.01)
let bodyMaterial = SCNMaterial()
bodyMaterial.diffuse.contents = UIColor(red: 0.15, green: 0.15, blue: 0.15, alpha: 1.0)
bodyMaterial.metalness.contents = 0.1
bodyMaterial.roughness.contents = 0.8
// Animated LED indicator
let ledNode = SCNNode(geometry: SCNCylinder(radius: 0.01, height: 0.005))
ledNode.geometry?.materials = [blueLEDMaterial]
let pulseAction = SCNAction.sequence([
SCNAction.fadeOpacity(to: 0.3, duration: 1.0),
SCNAction.fadeOpacity(to: 1.0, duration: 1.0)
])
ledNode.runAction(SCNAction.repeatForever(pulseAction))
// Dual antennas with proper positioning
let antenna1 = createAntenna()
antenna1.rotation = SCNVector4(0, 0, 1, Float.pi * 0.15)
let antenna2 = createAntenna()
antenna2.rotation = SCNVector4(0, 0, 1, -Float.pi * 0.15)
// Assembly with ventilation details
routerNode.addChildNode(bodyNode)
routerNode.addChildNode(ledNode)
routerNode.addChildNode(antenna1)
routerNode.addChildNode(antenna2)
// ... additional detail nodes
return routerNode
}Intelligent furniture evaluation for optimal extender placement:
- Height Constraints: 0.5m - 2.0m range for accessibility
- Furniture Preference: Tables > Counters > Sofas > Other
- Size Optimization: Larger surfaces score higher for stability
- Confidence Integration: Uses RoomPlan detection confidence
- Position Calculation: Centers device on surface with height offset
ARVisualizationManager Integration (~200 lines added):
- Device node management with visual effects
- Connection line rendering between devices
- Highlight animations and user interaction feedback
- Memory-efficient node pooling system
RoomCaptureViewController Integration:
- Router placement mode toggle
- Tap gesture handling for device positioning
- Automatic extender placement workflow
- Status updates and user feedback
FloorPlanViewController Integration:
- 2D device symbol rendering system
- Professional architectural symbols
- Connection line visualization
- Confidence indicator display
- Complete Room Scan: Finish RoomPlan capture to analyze furniture
- Surface Analysis: System automatically evaluates detected furniture
- Router Placement Mode: User taps "Place Router" to enter placement mode
- Interactive Positioning: User taps desired location in AR view
- Automatic Extender: System places extender on best available surface
- Visual Confirmation: Both devices appear in AR with connection line
- Floor Plan View: Devices shown on 2D architectural plans with symbols
- Efficient Rendering: Reuses 3D models and materials across devices
- Smart Updates: Only recalculates surfaces when room data changes
- Memory Management: Proper cleanup of AR nodes and animations
- Batch Operations: Groups surface analysis for better performance
- WiFi Range Calculation: Signal propagation modeling for smart placement
- Multiple Extenders: Support for mesh network configurations
- Coverage Visualization: Heat map overlays showing signal strength
- Advanced Analytics: Machine learning for placement optimization
- User Overrides: Manual extender positioning capability
- Minimum Requirements: iOS 17.0+, RoomPlan-compatible device
- 3D Model Scale: Realistic proportions (router: 25cm x 15cm x 5cm)
- Animation Performance: 60 FPS on device, optimized for battery life
- Memory Usage: ~2MB additional for 3D models and textures
- Surface Detection: Works with any RoomPlan-detected furniture
Decision: Manual start/stop buttons instead of automatic completion detection
Rationale: RoomPlan doesn't provide reliable completion signals; user knows best when they've captured enough data
Implementation: primaryActionTapped() switches between "Start/Stop Room Scan" based on isScanning state
Decision: Record measurements every 1 foot of movement instead of every second
Rationale: Prevents overwhelming the system with too many data points while ensuring adequate coverage
Implementation: simd_distance(location, lastPosition) >= 0.3048 (1 foot in meters)
Decision: Professional furniture symbols instead of simple rectangles Rationale: Makes floor plans immediately recognizable to technicians and customers Implementation: Specialized drawing methods for each furniture category with proper labels
Decision: Limited nodes (20 max), 2-second update intervals, simplified AR config
Rationale: Prevents device overheating and maintains smooth AR tracking
Implementation: Node pooling with maxNodes = 20 and updateInterval = 2.0
Primary Responsibility: UI state management and workflow coordination
Key Properties:
private var isScanning: Bool = false // Current scanning state
private var capturedRoomData: CapturedRoom? // Processed room data from RoomPlan
private var primaryActionButton: UIButton? // Context-sensitive main action
private var speedTestProgressView: UIProgressView? // Speed test visual feedbackState Management Logic:
func updateButtonStates() {
if isScanning {
primaryActionButton?.setTitle("Stop Room Scan", for: .normal)
} else if capturedRoomData == nil {
primaryActionButton?.setTitle("Start Room Scan", for: .normal)
} else if !wifiSurveyManager.isRecording {
primaryActionButton?.setTitle("Start WiFi Survey", for: .normal)
} else {
primaryActionButton?.setTitle("Stop WiFi Survey", for: .normal)
}
}Critical Methods:
primaryActionTapped(): Main user interaction handlerstartSession()/stopSession(): RoomPlan capture controlstartWiFiSurvey()/stopWiFiSurvey(): WiFi measurement controlupdateStatusLabel(): Visual feedback with color-coded backgrounds
Primary Responsibility: AI-powered room classification and furniture cataloging
Enhanced Classification Algorithm:
func classifyRoom(surface: CapturedRoom.Surface, objects: [CapturedRoom.Object]) -> RoomType {
// Step 1: Object-based scoring
var kitchenScore = 0, bedroomScore = 0, bathroomScore = 0
for object in nearbyObjects {
switch object.category {
case .refrigerator, .oven, .dishwasher: kitchenScore += 3
case .bed: bedroomScore += 4
case .toilet, .bathtub: bathroomScore += 4
case .sofa, .television: livingRoomScore += 3
// ... complete scoring logic
}
}
// Step 2: Find highest scoring room type
let maxScore = scores.max(by: { $0.1 < $1.1 })
// Step 3: Fallback to size-based classification if no objects
if maxScore?.1 == 0 {
return classifyRoomBySize(surface: surface)
}
return maxScore?.0 ?? .unknown
}
func classifyRoomBySize(surface: CapturedRoom.Surface) -> RoomType {
let area = calculateSurfaceArea(surface)
let aspectRatio = max(width, depth) / min(width, depth)
// Size-based heuristics
if area < 6.0 { return aspectRatio > 2.0 ? .hallway : .bathroom }
else if area < 12.0 { return aspectRatio > 2.0 ? .hallway : .bedroom }
else if area < 25.0 { return .bedroom }
else { return .livingRoom }
}Data Structures:
struct IdentifiedRoom {
let type: RoomType // Classification result
let bounds: CapturedRoom.Surface // Original RoomPlan data
let center: simd_float3 // Room center point
let area: Float // Calculated floor area
let confidence: Float // Classification confidence (0-1)
let wallPoints: [simd_float2] // Actual wall boundary points
let doorways: [simd_float2] // Door/opening positions
}Primary Responsibility: WiFi performance measurement and data coordination
Network Integration Architecture:
class WiFiSurveyManager {
// Network data integration (single source of truth)
private var networkDataCollector: NetworkDataCollector?
// Gets current network name from NetworkDataCollector
private func updateNetworkInfoFromCollector() {
currentNetworkName = networkDataCollector?.getCurrentNetworkName() ?? "Unknown"
currentSignalStrength = networkDataCollector?.getCurrentSignalStrength() ?? -70
}
}Real Speed Testing Implementation:
func performRealSpeedTest(completion: @escaping (Result<Double, SpeedTestError>) -> Void) {
guard !isRunningSpeedTest else { return }
isRunningSpeedTest = true
// Use 1MB download for speed calculation
let testURL = URL(string: "https://httpbin.org/bytes/1048576")!
let startTime = CFAbsoluteTimeGetCurrent()
// Progress tracking with timer
let progressTimer = Timer.scheduledTimer(withTimeInterval: 0.2, repeats: true) { [weak self] timer in
let elapsed = CFAbsoluteTimeGetCurrent() - startTime
let progress = min(Float(elapsed / 10.0), 0.95)
self?.speedTestProgressHandler?(progress, "Testing download speed...")
}
// Download task with completion handler
let task = session.downloadTask(with: request) { tempURL, response, error in
let duration = CFAbsoluteTimeGetCurrent() - startTime
let bytes = Double(fileSize)
let mbps = (bytes * 8 / duration) / 1_000_000
completion(.success(mbps))
}
}Distance-Based Recording:
func recordMeasurement(at location: simd_float3, roomType: RoomType?, floorIndex: Int?, roomId: UUID?) {
guard isRecording else { return }
// Only record if moved at least 1 foot
if let lastPosition = lastMeasurementPosition {
let distance = simd_distance(location, lastPosition)
guard distance >= measurementDistanceThreshold else { return }
}
lastMeasurementPosition = location
// Create and store measurement including floorIndex and roomId...
}Primary Responsibility: 3D AR visualization with performance optimization
Node Pooling System:
private var nodePool: [SCNNode] = []
private let maxNodes = 20
func addWiFiMeasurementVisualization(at position: simd_float3, measurement: WiFiMeasurement) {
// Performance optimization: Limit number of nodes
if measurementDisplayNodes.count >= maxNodes {
let oldestNode = measurementDisplayNodes.removeFirst()
oldestNode.removeFromParentNode()
nodePool.append(oldestNode) // Return to pool for reuse
}
let node = getOrCreateMeasurementNode(for: measurement)
// ... add to scene
}Room Outline Preservation:
func createRoomOutlines(from capturedRoom: CapturedRoom) {
// Create semi-transparent wall outlines
for wall in capturedRoom.walls {
let wallNode = createWallOutlineNode(from: wall)
// Thin white boxes showing wall positions
wallNode.geometry = SCNBox(width: wall.dimensions.x, height: wall.dimensions.y, length: 0.02)
wallNode.material.transparency = 0.7
}
}Primary Responsibility: 2D architectural floor plan rendering
Architectural Drawing System:
func drawArchitecturalDoor(context: CGContext, at center: CGPoint, scale: CGFloat) {
let doorWidth: CGFloat = 12 * scale / 50
// Door frame (opening in wall)
context.setStrokeColor(UIColor.white.cgColor)
context.move(to: CGPoint(x: center.x - doorWidth/2, y: center.y))
context.addLine(to: CGPoint(x: center.x + doorWidth/2, y: center.y))
context.strokePath()
// Door swing arc (architectural convention)
context.addArc(center: CGPoint(x: center.x - doorWidth/2, y: center.y),
radius: doorWidth, startAngle: 0, endAngle: .pi/2, clockwise: false)
context.strokePath()
// Door panel position
context.move(to: CGPoint(x: center.x - doorWidth/2, y: center.y))
context.addLine(to: CGPoint(x: center.x - doorWidth/2, y: center.y - doorWidth))
context.strokePath()
}Furniture Symbol Library: Each furniture type has a specialized drawing method following architectural conventions:
func drawBed(context: CGContext, at center: CGPoint, size: CGSize) {
// Bed frame outline
context.addRect(rect)
context.strokePath()
// Pillows at head of bed (20% of length)
let pillowRect = CGRect(x: rect.minX + 2, y: rect.minY + 2,
width: rect.width - 4, height: rect.height * 0.2)
context.setFillColor(UIColor.lightGray.cgColor)
context.addRect(pillowRect)
context.fillPath()
drawFurnitureLabel(context: context, text: "BED", at: center)
}
func drawSofa(context: CGContext, at center: CGPoint, size: CGSize) {
// Rounded rectangle for sofa body
context.addRoundedRect(in: rect, cornerWidth: 4, cornerHeight: 4)
context.drawPath(using: .fillStroke)
// Dashed lines for cushion divisions
context.setLineDash(phase: 0, lengths: [3, 2])
let cushionWidth = size.width / 3
for i in 1..<3 {
let x = rect.minX + CGFloat(i) * cushionWidth
context.move(to: CGPoint(x: x, y: rect.minY + 2))
context.addLine(to: CGPoint(x: x, y: rect.maxY - 2))
}
context.strokePath()
}- Node Pooling: Reuse AR nodes instead of constant creation/destruction
- Limited Node Count: Maximum 20 AR measurement nodes at any time
- Weak References: All closures use
[weak self]to prevent retain cycles - Cleanup Methods: Explicit removal of AR nodes and timers
// Simplified AR configuration for better performance
let configuration = ARWorldTrackingConfiguration()
configuration.sceneReconstruction = .mesh // Remove classification
configuration.environmentTexturing = .none // Disable texturing
// Disable person segmentation for performance- Background Threading: Network requests don't block UI
- Progress Callbacks: Real-time feedback prevents user confusion
- Error Handling: Graceful degradation when network tests fail
- Throttled Measurements: Distance-based instead of time-based
1. RoomPlan Capture Failures
- Symptom:
captureView(didPresent:error:)called with error - Cause: Poor lighting, insufficient LiDAR data, or device movement too fast
- Solution: Status messages guide user to move slower and ensure good lighting
2. AR Tracking Performance Issues
- Symptom: "poor slam" messages in console, AR nodes jumping
- Cause: Device overheating, insufficient processing power
- Solution: Reduced AR complexity, node pooling, update throttling
3. WiFi Speed Test Failures
- Symptom:
SpeedTestErrorin completion handler - Cause: Network connectivity issues, server unavailable
- Solution: Graceful fallback to last known speed, user notification
4. Room Classification Inaccuracy
- Symptom: Wrong room types detected
- Cause: Insufficient or ambiguous furniture objects
- Solution: Fallback to size-based classification with confidence metrics
// Comprehensive logging with emoji prefixes for easy filtering
print("π Classifying room with \(nearbyObjects.count) nearby objects")
print("π WiFi measurement #\(measurements.count) recorded")
print("π― Adding AR visualization for measurement")
print("β οΈ Invalid coverage value: \(coverage) at position \(position)")- RoomPlan Framework: Apple's 3D room capture system
- ARKit: Augmented reality visualization platform
- Network Framework: Real-time connectivity monitoring
- SceneKit: 3D node rendering and management
- Core Graphics: 2D floor plan rendering
// Potential cloud sync integration point
extension WiFiSurveyManager {
func syncToSpectrumCloud() {
// Upload room data and measurements to Spectrum backend
// Implement OAuth authentication
// Handle offline data queuing
}
}
// Potential IoT device integration
extension RoomAnalyzer {
func detectSmartDevices() -> [IoTDevice] {
// Scan for Spectrum-compatible smart home devices
// Map device locations to room layout
// Provide connectivity recommendations
}
}- Room Classification Logic: Test with various furniture combinations
- WiFi Measurement Distance Calculations: Verify 1-foot threshold accuracy
- AR Node Pooling: Ensure proper cleanup and reuse
- Speed Test Calculations: Validate Mbps calculations with known data sizes
- Room scanning works in various lighting conditions
- AR tracking remains stable during WiFi survey
- Floor plans render correctly with all furniture types
- Speed test progress indicators function properly
- App handles network connectivity loss gracefully
This enhanced documentation provides complete context for future development work, including architectural decisions, implementation details, common issues, and extension points. Any developer should be able to understand and modify the codebase without requiring additional AI assistance.
- Primary Blue:
UIColor(red: 0.0, green: 0.122, blue: 0.247, alpha: 1.0) - Accent Colors: Green, Orange, Silver for different states
- Typography: System fonts with appropriate weights and sizes
- Button Styles: Primary, Secondary, Accent with consistent styling
- Doors: Arc showing swing direction with frame opening
- Furniture: Realistic symbols with text labels
- Beds: Rectangle with pillow area
- Sofas: Rounded rectangle with cushion divisions
- Tables: Circle (round) or rectangle (rectangular)
- Appliances: Specialized symbols with identifying features
- Rooms: Actual wall boundaries instead of simple rectangles
- π± Scanning: Move around to capture room layout
- π Ready for Results: Data collected and available for analysis
- π‘ Measuring: WiFi survey in progress with point count
- π Data Available: Survey data collected and ready to view
- π³ Surface Detection: Light double-pulse when walls/floors discovered
- π³ Object Recognition: Medium triple-pulse when furniture identified
- π³ Major Discovery: Heavy confirmation pattern for room completion
- π³ Scanning Patterns: Rapid pulse sequences simulating scanner beam movement
- π³ Intelligent Throttling: Prevents haptic overload with 0.5s minimum intervals
- π Persistent AR Markers: Color-coded floor indicators showing where tests were conducted
- π¨ Signal Quality Colors: Green (excellent) β Yellow (good) β Orange (fair) β Red (poor)
- π Coverage Analysis: Visual indication of survey completeness and gaps
- π Memory Efficient: Separate from measurement nodes with 50-marker limit
- π± Floor Plan Integration: Test points displayed on 2D architectural plans
- Node Pooling: Reuse AR nodes to reduce memory allocation
- Limited Nodes: Maximum 20 measurement nodes for smooth performance
- Reduced Complexity: Simplified AR configuration for better tracking
- Update Throttling: 2-second intervals to reduce processing load
- Distance-Based: Test every 2 feet of movement for optimal coverage
- Immediate Response: 300ms trigger time for responsive speed testing
- Progress Tracking: Visual feedback during speed tests
- Error Handling: Graceful fallback when network tests fail
- Background Processing: Non-blocking network operations
- Cleanup Methods: Proper removal of AR nodes and listeners
- Weak References: Prevent retain cycles in callbacks
- Efficient Data Structures: Optimized for large measurement datasets
- Bounds Checking: Automatic limits on measurements (500) and position history (50)
- Memory Cleanup: Comprehensive deallocation cleanup in deinit methods
- Haptic Management: Proper cleanup and re-initialization of haptic generators
print("π Classifying room with \(nearbyObjects.count) nearby objects")
print("π WiFi measurement #\(measurements.count) recorded at (\(location.x), \(location.y), \(location.z))")
print("π― Adding AR visualization for measurement at (\(position.x), \(position.y), \(position.z))")
print("π³ Scanning haptic triggered for surface detection")
print("π§Ή Trimmed 15 old measurements to maintain memory bounds (now 500/500)")
print("π¦ Object bed detected with confidence: 0.85")
print("π― Room confidence breakdown - Surface: 0.92, Furniture: 0.80, Objects: 0.85, Combined: 0.87")- Room classification process with object detection
- WiFi measurement collection with location tracking
- AR node creation and positioning
- Speed test progress and results
- Haptic feedback events and throttling
- Memory management and bounds checking operations
- RoomPlan confidence scoring and weighted calculations
- Object detection confidence for individual furniture items
- Device Connection Monitoring: Real-time tracking of device connectivity across routers/extenders
- Band Steering Control: Automated steering between 2.4GHz, 5GHz, and 6GHz bands for comprehensive signal data
- Router/Extender Handoffs: Systematic device switching to gather coverage data from all access points
- Data Correlation: Sub-second timestamp matching between location measurements and Plume API connection data
- Steering Orchestration: Intelligent workflow coordinating band/device changes with user movement patterns
- Signal Validation: Cross-reference app measurements with Plume's network analytics for accuracy verification
- Cloud Sync: Store room layouts and measurements in Spectrum backend
- Historical Analysis: Track WiFi performance over time
- Advanced Analytics: Machine learning for optimal router placement
- Multi-Floor Support: Handle complex building layouts
- Professional Reporting: PDF generation with detailed technical specifications
- Survey Guidance: Real-time suggestions for optimal test point placement
- Coverage Gap Detection: Automatic identification of untested areas
- Test Point Clustering: Smart grouping of nearby measurements
- Survey Completeness Scoring: Percentage-based coverage assessment
- Plume API Integration: Device steering and connection monitoring for comprehensive WiFi analysis
- Spectrum Systems: Connect with customer service and technical support
- IoT Integration: Monitor smart home device connectivity
- Network Optimization: Automatic router configuration recommendations
The Plume API integration extends the existing WiFi analysis capabilities with active network control and real-time device monitoring. This creates a comprehensive system that can gather signal data across all available bands and devices while tracking user movement through their home.
Central coordinator for all Plume interactions:
class PlumeAPIManager: ObservableObject {
@Published var connectedDevices: [PlumeDevice] = []
@Published var availableBands: [WiFiFrequencyBand] = []
@Published var currentConnection: PlumeConnection?
// Device connection monitoring
func monitorDeviceConnections() async
func getConnectionStatus(for deviceMAC: String) -> PlumeConnectionStatus
// Band steering operations
func steerToBand(_ band: WiFiFrequencyBand) async throws
func steerToDevice(_ deviceID: String) async throws
// Data correlation
func getConnectionHistory(from startTime: Date, to endTime: Date) -> [PlumeConnectionEvent]
}Coordinates steering operations with location-based measurements:
class PlumeSurveyOrchestrator {
private let plumeAPI: PlumeAPIManager
private let wifiSurveyManager: WiFiSurveyManager
// Steering workflow management
func beginComprehensiveSurvey(at location: simd_float3) async
func performBandCycling() async -> [SteeringMeasurement]
func performDeviceHandoffs() async -> [DeviceConnectionData]
// Movement-triggered analysis
func onUserMovement(to location: simd_float3) async
}Matches location measurements with Plume connection data:
struct DataCorrelationEngine {
// Timestamp correlation with Β±2 second tolerance
func correlateLocationData(_ measurements: [WiFiMeasurement],
with plumeData: [PlumeConnectionEvent]) -> [CorrelatedDataPoint]
// Location-based device mapping
func mapDeviceToLocation(_ device: PlumeDevice,
using measurements: [WiFiMeasurement]) -> LocationMapping
// Signal validation between sources
func validateSignalStrength(_ appMeasurement: Float,
against plumeReading: Float) -> ValidationResult
}Extends current measurement collection with Plume coordination:
extension WiFiSurveyManager {
// Enhanced measurement with Plume context
func recordMeasurementWithPlumeData(at location: simd_float3,
roomType: RoomType?,
plumeContext: PlumeConnectionContext) {
// Existing measurement logic
// + Plume API state capture
// + Data correlation tagging
}
// Movement-triggered steering workflow
func onSignificantMovement(to location: simd_float3) {
// Existing distance checking
// + Trigger Plume steering orchestration
// + Coordinated multi-source data collection
}
}struct PlumeMeasurement {
let location: simd_float3
let timestamp: Date
let appSignalStrength: Int
let plumeSignalStrength: Int
let connectedDevice: PlumeDevice
let currentBand: WiFiFrequencyBand
let steeringHistory: [SteeringEvent]
let correlationConfidence: Float // 0-1 matching accuracy
}struct SteeringEvent {
let eventType: SteeringType // bandChange, deviceHandoff
let fromState: ConnectionState
let toState: ConnectionState
let timestamp: Date
let stabilizationTime: TimeInterval // Time to signal stability
let location: simd_float3
}- Movement Detection β Existing distance threshold (3 feet) triggers new location
- Plume State Capture β Query current connection (device, band, signal strength)
- Baseline Measurement β Record current state with app's signal measurement
- Steering Sequence β Cycle through bands: 2.4β5β6GHz at current location
- Device Handoffs β Switch routerβextenderβrouter with measurements at each
- Data Correlation β Match all measurements with Plume timestamps/locations
- Optimal Return β Steer back to best performing configuration
- Sub-second Correlation: Match measurements within Β±2 second window
- Location Validation: Cross-reference position data between app and inferred device proximity
- Signal Verification: Compare app RSSI with Plume's signal strength readings
- Confidence Scoring: Rate correlation accuracy based on timestamp precision and location consistency
- Steering Throttling: 5-second minimum between band changes for signal stabilization
- Batch Operations: Group multiple steering commands when possible
- Background Monitoring: Continuous connection monitoring without blocking UI
- Correlation History: Limit to 1000 most recent correlation points
- Steering Events: Maintain sliding window of last 500 steering operations
- Data Cleanup: Automatic pruning of correlation data older than 24 hours
- Offline Mode: Continue app-only measurements when Plume API unavailable
- Partial Data: Proceed with available steering capabilities if some API features fail
- Retry Logic: Exponential backoff for failed steering commands
- Timeout Handling: 30-second timeout for steering operations
- State Recovery: Return to previous configuration if steering fails
- User Notification: Transparent feedback about steering status and any limitations
- Pattern Recognition: Learn optimal steering sequences based on room types
- Predictive Steering: Pre-steer based on user movement patterns
- Coverage Optimization: ML-driven recommendations for device placement
- Heat Map Enhancement: Overlay Plume-verified signal data on existing visualizations
- Device Performance: Compare router vs. extender performance by location
- Band Utilization: Track optimal band selection patterns throughout home
This Plume integration transforms the app from passive WiFi analysis to active network optimization, providing unprecedented insight into WiFi performance across all available devices and frequency bands.
The NetworkDataCollector serves as the single source of truth for all network information in the app, eliminating duplication and providing a clean separation of concerns.
Cellular Data Collection:
- Carrier information (name, MCC, MNC, country codes)
- Radio technology detection (5G, LTE, 3G, CDMA)
- Signal strength estimation (converted to dBm)
- Data connection state and roaming status
- Dual SIM support for multiple carriers
WiFi Network Detection:
- Current connected network (SSID, BSSID)
- Network path monitoring (WiFi/Cellular/Ethernet)
- Connection quality metrics (expensive/constrained status)
Location Services:
- Home location capture for coverage analysis
- GPS coordinates with each measurement
- Location-based network correlation
WiFiSurveyManager Integration:
// WiFiSurveyManager queries NetworkDataCollector for network info
private func updateNetworkInfoFromCollector() {
currentNetworkName = networkDataCollector?.getCurrentNetworkName() ?? "Unknown"
currentSignalStrength = networkDataCollector?.getCurrentSignalStrength() ?? -70
}
// Network data collected alongside WiFi measurements
let networkData = collector.collectCurrentData(at: location)Key Benefits:
- No Duplication: Single NWPathMonitor, single network info source
- Lightweight Design: Data collection only, no analysis
- Auto-Integration: Seamlessly provides data to existing WiFi workflow
- Future-Ready: Cellular data ready for router backup analysis
Network data is included in the unified export system:
{
"measurements": [...], // WiFi performance data
"networkData": [ // Cellular + network information
{
"cellularData": {
"carriers": {"slot1": {"name": "Verizon", ...}},
"radioTechnologies": {"slot1": "5G"},
"signalBars": 4
},
"wifiData": {
"connectedSSID": "MyNetwork",
"connectedBSSID": "aa:bb:cc:dd:ee:ff"
},
"location": {"x": 1.2, "y": 0.0, "z": -2.1}
}
]
}This architecture provides comprehensive network analysis while maintaining clean code organization and preventing duplication between components.
- Non-LiDAR Device Handling: Graceful degradation with red placeholder view instead of blocking alerts
- Accessible Features: WiFi analysis, floor plan view, and report generation work on all devices
- Clear User Messaging: Informative placeholder explains available features when room capture unavailable
- ITU Indoor Path Loss: Industry-standard propagation models for accurate signal prediction
- Multi-band Support: Comprehensive 2.4GHz, 5GHz, and 6GHz (WiFi 7) frequency analysis
- Environment Factors: Accounts for residential, office, commercial, and industrial environments
- Floor Penetration: Models signal loss through floors (15dB per floor)
- Coverage Confidence: Weighted scoring based on signal strength, band diversity, and consistency
- Propagation Testing: Built-in validation suite for RF calculations
- Distance-based Path Loss: Accurate signal strength prediction at various distances
- Multi-band Measurements: Simultaneous analysis across all WiFi frequency bands
- Professional Accuracy Metrics: Confidence scoring and prediction accuracy in reports
- iOS 17.0+: Required for full RoomPlan functionality
- ARKit Support: iPhone/iPad with LiDAR sensor recommended (but not required)
- Network Access: WiFi connection required for speed testing
- Device Heat: Extended AR sessions may cause device warming
- Battery Usage: 3D scanning and AR rendering are power-intensive
- Storage: Room data and measurements require local storage space
Device: Set the run destination to an iOS 17+ device with a LiDAR Scanner for full functionality.
Simulator: iOS Simulator is now supported for UI testing with mock data (no hardware required).
- Fixed Floor Plan Display: Resolved missing floor plan renderer in scroll view layout
- Architectural Doorways: Professional doorway gaps integrated into wall structures with proper orientation
- Wall-Aware Positioning: Doorways now calculate nearest wall angle for correct placement
- Scrollable Content: Added proper scroll view container for better content organization
- Toggle Control Alignment: Fixed constraint issues with WiFi heatmap, debug, and coverage confidence controls
- Unobstructed 3D View: Repositioned bottom navigation buttons 64 points higher to prevent obstruction of RoomPlan 3D model
- Button Text Visibility: Fixed WiFi survey button text truncation with adaptive font sizing and increased width constraints
- User-Controlled Completion: Removed premature "survey complete" messages - only user can declare completion via explicit "Results" button tap
- Clear Status Messages: Status label now shows "π Data available - Use 'Results' button when you're ready to view analysis" instead of automatic completion
- Scroll View Architecture: Added
UIScrollViewwithcontentViewfor proper layout hierarchy - Doorway Algorithm:
findNearestWall()calculates wall angles usingatan2()for precise orientation - Constraint Updates: All controls now reference
contentViewinstead of mainviewfor proper positioning - Sample Data Integration: Added comprehensive demo data with 3 rooms, 4 furniture items, and 10 WiFi measurements
- Button positioning: Moved from
bottomAnchor.constraint(constant: -16)toconstant: -80 - Button width: Increased scan/survey toggle from 180pt to 200pt maximum width
- Font adaptation: Added
adjustsFontSizeToFitWidth = truewithminimumScaleFactor = 0.8 - Mode transitions: Removed automatic
.completedmode setting - only occurs on explicit user action
- Deployment Target: iOS 17.0 or later
- Frameworks: RoomPlan, ARKit, SceneKit, Network, Core Graphics
- Entitlements: Camera usage, WiFi access
- Device: iPhone/iPad with LiDAR sensor (iPhone 12 Pro or later, iPad Pro 2020 or later)
<key>NSCameraUsageDescription</key>
<string>This app requires access to your camera to use the LiDAR scanner for room mapping and WiFi analysis.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Location access is needed to identify WiFi networks accurately.</string>Problem: SpectrumBranding.swift not found during build
Solution: Ensure file is added to target in project.pbxproj:
/* SpectrumBranding.swift in Sources */ = {isa = PBXBuildFile; fileRef = [UUID] /* SpectrumBranding.swift */; };
Problem: NWPath ambiguity error Solution: Use explicit Network framework import:
import Network
// Use Network.NWPath instead of just NWPathProblem: RoomPlan availability warnings Solution: Wrap RoomPlan usage in availability checks:
if #available(iOS 17.0, *) {
roomAnalyzer.analyzeCapturedRoom(processedResult)
}Problem: CapturedRoom.Confidence type conversion errors
Solution: RoomPlan's Confidence is an enum (.high, .medium, .low), not a Float:
private func confidenceToFloat(_ confidence: CapturedRoom.Confidence) -> Float {
switch confidence {
case .high: return 0.9
case .medium: return 0.6
case .low: return 0.3
}
}Problem: App crashes on launch with NSUnknownKeyException (Fixed)
Root Cause: Broken storyboard outlet connections to non-existent properties
Error: '[<RoomCaptureViewController> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key cancelButton'
Solution: Remove broken outlet connections in Main.storyboard:
<!-- Remove these broken connections -->
<outlet property="cancelButton" destination="6LV-FR-JQF" id="oID-mD-Z4l"/>
<outlet property="doneButton" destination="MQz-pc-UhC" id="5nF-0P-w1J"/>Problem: App crashes on simulator (Legacy Issue - Now Fixed) Root Cause: ARKit and LiDAR not available on simulator Solution: App now includes comprehensive simulator support with mock data:
#if targetEnvironment(simulator)
print("π Running in simulator - bypassing RoomPlan compatibility check")
#else
if !RoomCaptureSession.isSupported {
showUnsupportedDeviceAlert()
}
#endifProblem: Not sure when scanning is "complete" Root Cause: No automatic completion detection in RoomPlan Solution: User decides completion based on their needs - app shows "Ready for Results" when data is available
Problem: WiFi measurements not appearing in AR Root Cause: AR session not starting properly Debug Steps:
- Check
arVisualizationManager.isARActiveis true - Verify
switchToARMode()callsstartARSession() - Look for AR permission errors in console
Problem: Floor plan shows no walls, only furniture Root Cause: Wall extraction failing from RoomPlan data Debug Steps:
- Check
room.wallPoints.countin logs - Verify
extractWallPoints()finds nearby walls - Fallback to rectangular room shape if no walls detected
Problem: App becomes unresponsive during WiFi survey Root Cause: Too many AR nodes or measurements Solution: Verify node pooling is working:
// Check current node count doesn't exceed limit
if measurementDisplayNodes.count >= maxNodes {
// Remove oldest nodes
}Problem: Device overheating during extended use Root Cause: Intensive AR processing Solution: Reduce AR complexity:
configuration.sceneReconstruction = .mesh // Not .meshWithClassification
configuration.environmentTexturing = .noneProblem: Speed tests timing out Root Cause: Network connectivity or server issues Debug Steps:
- Test with known good network connection
- Check
speedTestProgressHandleris being called - Verify URL
https://httpbin.org/bytes/1048576is accessible
- Add case to
CapturedRoom.Object.Category(if not already present) - Update scoring in
RoomAnalyzer.classifyRoom():
case .newFurnitureType:
appropriateRoomScore += scoreValue- Create drawing method in
FloorPlanViewController:
func drawNewFurniture(context: CGContext, at center: CGPoint, size: CGSize) {
// Follow architectural symbol conventions
// Include appropriate text label
}- Add case to
drawArchitecturalFurniture()switch statement
- Add case to
RoomTypeenum:
case newRoomType = "New Room Type"- Update classification scoring in
classifyRoom() - Add color in
roomTypeColor()method - Update size-based fallback logic if appropriate
Current: Every 1 foot of movement (0.3048 meters)
private let measurementDistanceThreshold: Float = 0.3048To change frequency, modify this constant:
- More frequent:
0.1524(6 inches) - Less frequent:
0.6096(2 feet)
Node limit (currently 20):
private let maxNodes = 20Update frequency (currently 2 seconds):
private let updateInterval: TimeInterval = 2.0- iPhone 12 Pro or later: LiDAR sensor required for full functionality
- iOS Simulator: Supported for UI testing with mock data
- iOS 17.0+: RoomPlan framework availability
- Good lighting: Avoid dark environments (device testing only)
- WiFi network: Connected network for speed testing
- Clear space: 10+ feet scanning area for best results (device testing only)
Room Scanning Test (Device):
- Start in corner of room
- Move device slowly (1-2 feet per second)
- Capture all walls, floor, and major furniture
- Stop manually when satisfied with coverage
- Verify room type classification is reasonable
Room Scanning Test (Simulator):
- Launch app in iOS Simulator
- Verify "SIMULATOR MODE" label appears with mock camera
- Start room scan - progress bar should simulate scanning
- Stop scan - should generate mock room with furniture
- Verify room classification works with mock data
WiFi Survey Test (Both Device & Simulator):
- Switch to WiFi survey mode
- Verify AR mode displays room outlines (or mock AR in simulator)
- Move around systematically (or click different areas in simulator)
- Check speed test progress indicators appear
- Confirm measurements recorded in visualization
Floor Plan Test (Both Device & Simulator):
- Navigate to floor plan view
- Verify room shapes render correctly
- Check furniture symbols are recognizable
- Test door symbols show proper swing arcs
- Toggle heatmap overlay functionality
- Memory Usage: Should not exceed 200MB during normal operation
- Frame Rate: AR view should maintain 30+ FPS
- Speed Test Duration: 5-15 seconds per test depending on network
- Room Analysis: Complete within 2-3 seconds after scan stop
Use these filters in Xcode console to isolate relevant logs:
π- Room analysis and classificationπ- WiFi measurement recordingπ―- AR visualization creationβ οΈ- Warnings and validation errorsπ‘- Network and speed testingπ³- Haptic feedback events and patternsπ§Ή- Memory management and cleanup operationsπ¦- Object detection and confidence scoringπ―- Room confidence calculations and breakdowns
"π Classifying room with 3 nearby objects"
β Room classification in progress, found 3 furniture items
"π WiFi measurement #15 recorded at (1.2, 0.5, -2.1)"
β Successfully recorded 15th measurement at specific 3D position
"β οΈ Insufficient coverage data points for heatmap: 1"
β Need more measurements for heatmap generation
"Skipping integration due to poor slam"
β AR tracking quality degraded, reduce AR complexity
"π³ Scanning haptic triggered for surface detection"
β Wall/floor discovered, light haptic feedback provided
"π³ [Simulator] Would trigger scanning haptic for object detection"
β Simulator mode logging for haptic events (no actual vibration)
"π§Ή Trimmed 15 old measurements to maintain memory bounds (now 500/500)"
β Automatic cleanup removed old data to prevent memory growth
"π§Ή RoomCaptureViewController deallocating - performing final cleanup"
β Controller cleanup ensuring no memory leaks on exit
"π¦ Object bed detected with confidence: 0.85"
β RoomPlan detected furniture with 85% confidence score
"π― Room confidence breakdown - Surface: 0.92, Furniture: 0.80, Objects: 0.85, Combined: 0.87"
β Weighted confidence calculation showing all components and final score
Use Xcode Instruments to monitor:
- AR Node Count: Should not continuously increase
- Timer References: Ensure all timers are invalidated
- Closure Captures: Check for strong reference cycles
Single Floor Limitation:
- Current: Only handles single-floor layouts
- Future: Multi-floor detection using altitude changes
- Implementation: Extend
RoomAnalyzerwith floor grouping logic
Local Data Storage:
- Current: All data stored in memory during session
- Future: Core Data persistence for historical analysis
- Implementation: Add data model layer with sync capabilities
Network Testing Accuracy:
- Current: Simple download speed test
- Future: Comprehensive latency, jitter, and packet loss analysis
- Implementation: Extend
WiFiSurveyManagerwith advanced metrics
Custom Branding Integration:
// Extend SpectrumBranding for white-label versions
extension SpectrumBranding {
static func configureForPartner(_ partner: String) {
// Load partner-specific colors, fonts, logos
}
}Advanced Analytics Integration:
// Add analytics tracking throughout app
extension RoomCaptureViewController {
func trackUserAction(_ action: String, parameters: [String: Any]) {
// Send to analytics service
}
}Cloud Sync Preparation:
// Protocol for future cloud sync implementation
protocol CloudSyncable {
func uploadToCloud() async throws
func downloadFromCloud() async throws
}This comprehensive documentation provides complete context for understanding, maintaining, and extending the Spectrum WiFi Analyzer app without requiring additional AI assistance.
This application demonstrates the integration of Apple's latest AR technologies with real-world network analysis use cases, creating a professional tool for WiFi assessment and optimization.