Skip to content

Add WiFiHeatmap widget to the ensemble#2164

Open
M-Talha4 wants to merge 3 commits intomainfrom
features/wifi-heatmap
Open

Add WiFiHeatmap widget to the ensemble#2164
M-Talha4 wants to merge 3 commits intomainfrom
features/wifi-heatmap

Conversation

@M-Talha4
Copy link

@M-Talha4 M-Talha4 commented Feb 15, 2026

WiFiHeatmap Widget Documentation

Overview

The WiFiHeatmap widget is a Flutter-based visualization tool that allows you to create WiFi signal strength heatmaps by walking through a space and recording signal measurements at different locations. It overlays a color-coded heatmap on your floor plan image, showing areas of strong and weak WiFi coverage.

What It Does

The WiFiHeatmap widget helps you:

  • Visualize WiFi Coverage: See signal strength across your entire space with color-coded heatmap
  • Identify Dead Zones: Quickly spot areas with poor WiFi coverage
  • Optimize Router Placement: Place modems and routers on your floor plan to plan network layout
  • Track Your Path: Records your movement path as you scan different areas
  • Real-time Signal Integration: Continuously capture WiFi signal strength data from external sources

How It Works

Setup Mode

  1. Upload your floor plan image (PNG, JPG, etc.)
  2. Tap the modem button (red) to place your primary WiFi modem
  3. Tap the router button (blue) to add additional routers/access points
  4. Drag devices to position them accurately on the floor plan
  5. Tap the start button (green) to Continue

Scanning Mode

  1. Walk to a location in your space
  2. The widget shows a location pin where you'll record
  3. Tap "Add Checkpoint" to record the WiFi signal at that location
  4. Move to the next location and repeat
  5. The widget automatically:
    • Measures signal strength between checkpoints
    • Interpolates signal values along your path
    • Updates the heatmap with color-coded signal strength

Signal Strength Colors

  • 🟢 Green: Excellent signal (≥ -50 dBm)
  • 🟡 Yellow: Good signal (-60 to -70 dBm)
  • 🟠 Orange: Fair signal (-70 to -80 dBm)
  • 🔴 Red: Poor signal (< -90 dBm)

Basic Usage

Minimal Setup (Just Get Started)

View:
  body:
    Column:
      children:
        - WiFiHeatmap:
            id: myHeatmap
            floorPlan: imagePath
            gridSize: 12

Real-time Signal Monitoring with API Integration

This example demonstrates how to continuously collect WiFi signal strength data from an API and integrate it with the heatmap:

View:
  body:
    Column:
      padding: 100 16
      gap: 16

      children:
        - Button:
            label: Stop Timer
            onTap:
              stopTimer:
                id: myTimer

        - WiFiHeatmap:
            id: testHeatmap
            floorPlan: /path/to/your/floorplan.jpg
            gridSize: 5
            signalValues: []

            # Actions / Events
            onMessage:
              showSnackBar:
                message: ${message}
                duration: 2800

            # Triggered when user adds first checkpoint
            onFirstCheckpoint:
              startTimer:
                id: myTimer
                onTimer:
                  invokeAPI:
                    name: getSignalStrength
                options:
                  repeat: true
                  repeatInterval: 1  # Poll every 1 second

            # Triggered when all grid cells are filled
            onAllGridsFilled:
              stopTimer:
                id: myTimer

API:
  getSignalStrength:
    url: http://localhost:3000/api/dbm
    method: GET
    mockResponse:
      statusCode: 200
      body:
        dbm: ${Math.floor(Math.random() * (-30 - (-100) + 1)) + (-100)}

    onResponse: |-
      //@code
      console.log("API response received: " + response.body);
      if (response.body.dbm) {
        // Store signal value with timestamp
        ensemble.storage.dbmList.push({
          dbm: response.body.dbm,
          timestamp: Date.now()
        });
        
        // Update widget's signalValues property
        testHeatmap.signalValues = ensemble.storage.dbmList;
      }

Global: |-
  // Initialize storage for signal values
  ensemble.storage.dbmList = [];
  app.useMockResponse = true;

How Signal Values Work

The widget now supports real-time signal value collection with timestamps:

  1. Signal Value Format: Each signal value is an object with:

    {
      dbm: -65,        // Signal strength in dBm
      timestamp: 1234567890  // Unix timestamp in milliseconds
    }
  2. Continuous Collection: Signal values are collected continuously while scanning, not just at checkpoints

  3. Smart Distribution: When you add a checkpoint:

    • All signal values between the previous checkpoint and current checkpoint are retrieved based on timestamps
    • These values are intelligently distributed across the grid cells along your path
    • Creates more accurate and granular heatmap representation
  4. Checkpoint Timing:

    • First checkpoint: Records timestamp and triggers onFirstCheckpoint event
    • Subsequent checkpoints: Uses timestamp range to map signal values to grid cells
    • Grid cells between checkpoints are filled with actual measured values instead of interpolation

Full Customization Example

View:
  title: WiFi Coverage Analyzer

  body:
    Column:
      styles:
        padding: 16
        gap: 16

      children:
        - WiFiHeatmap:
            id: wifiAnalyzer
            # REQUIRED
            floorPlan: image
            # PERFORMANCE
            gridSize: 16   # 12-16 recommended | 20+ high detail but slower

            # Signal values from external source
            signalValues: ${ensemble.storage.dbmList}

            modemIcon:
              name: wifi_tethering
              size: 26

            routerIcon:
              name: router
              size: 26

            locationPinIcon:
              name: place
              size: 48

            deviceStyles:
              markerSize: 42
              modemColor: "#D32F2F"
              routerColor: "#1976D2"
              borderColor: white
              borderWidth: 3

            signalStyles:
              excellentColor: "#1B5E20"   # >= -50 dBm
              veryGoodColor: "#2E7D32"    # >= -60 dBm
              goodColor: "#FFEB3B"        # >= -70 dBm
              fairColor: "#FF9800"        # >= -80 dBm
              poorColor: "#FF5722"        # >= -90 dBm
              badColor: "#C62828"         # < -90 dBm

            heatmapStyles:
              fillAlpha: 150   # 0-255 (higher = stronger overlay)

            gridStyles:
              lineWidth: 0.8
              alpha: 70
              lineColor: black

            scanPointStyles:
              dotSizeFactor: 0.5
              color: "#1E88E5"
              borderWidth: 2

            locationPinStyles:
              size: 50
              color: "#E91E63"

            pathStyles:
              color: "#1565C0"
              width: 3

            buttonStyles:
              startScanColor: "#43A047"
              addCheckpointColor: "#1E88E5"

            # Event Handlers
            onMessage:
              showSnackBar:
                message: ${message}

            onFirstCheckpoint:
              startTimer:
                id: signalTimer
                onTimer:
                  invokeAPI:
                    name: getSignalStrength
                options:
                  repeat: true
                  repeatInterval: 1

            onAllGridsFilled:
              executeCode:
                body: |-
                  //@code
                  console.log("Heatmap complete!");
                  stopTimer.id = 'signalTimer';

Properties Reference

Core Properties

Property Type Required Default Description
floorPlan String - Path to floor plan image
gridSize Integer 12 Grid resolution (4-32)
signalValues List [] Array of signal measurements with timestamps

Signal Values Format

// Individual signal value object
{
  dbm: -65,              // Signal strength in dBm (integer)
  timestamp: 1234567890  // Unix timestamp in milliseconds (integer)
}

// Example array
[
  { dbm: -52, timestamp: 1709000000000 },
  { dbm: -58, timestamp: 1709000001000 },
  { dbm: -62, timestamp: 1709000002000 }
]

Note: The widget automatically handles conversion if you pass just dBm values without timestamps - it will assign current timestamps. However, for accurate path-based heatmap generation, always provide timestamps.

Style Properties

Device Styles

deviceStyles:
  markerSize: 42          # Size of device markers (default: 32)
  iconSize: 26            # Size of icons inside markers (default: 20)
  borderWidth: 3          # Border thickness (default: 2.8)
  borderColor: white      # Border color (default: white)
  modemColor: "#D32F2F"   # Modem marker color (default: red)
  modemIconColor: white   # Modem icon color (default: white)
  routerColor: "#1976D2"  # Router marker color (default: blue)
  routerIconColor: white  # Router icon color (default: white)

Signal Styles

signalStyles:
  excellentColor: "#1B5E20"  # >= -50 dBm (default: #388E3C)
  veryGoodColor: "#2E7D32"   # >= -60 dBm (default: #66BB6A)
  goodColor: "#FFEB3B"       # >= -70 dBm (default: #AFB42B)
  fairColor: "#FF9800"       # >= -80 dBm (default: #F57C00)
  poorColor: "#FF5722"       # >= -90 dBm (default: #E64A19)
  badColor: "#C62828"        # < -90 dBm (default: #C62828)

Heatmap Styles

heatmapStyles:
  fillAlpha: 150  # Opacity of heatmap overlay: 0-255 (default: 123)

Grid Styles

gridStyles:
  lineWidth: 0.8   # Grid line thickness (default: 0.6)
  alpha: 70        # Grid line opacity: 0-255 (default: 60)
  lineColor: black # Grid line color (default: black)

Scan Point Styles

scanPointStyles:
  dotSizeFactor: 0.5      # Checkpoint dot size relative to cell (default: 0.4)
  color: "#1E88E5"        # Checkpoint dot color (default: blueAccent)
  borderColor: "#FFFFFF"  # Checkpoint dot border (default: white with alpha)
  borderWidth: 2          # Checkpoint dot border width (default: 1.8)

Location Pin Styles

locationPinStyles:
  size: 50         # Pin size in pixels (default: 44)
  color: "#E91E63" # Pin color (default: red)

Path Styles

pathStyles:
  color: "#1565C0"  # Path line color (default: #1976D2)
  width: 3          # Path line width (default: 2.8)

Button Styles

buttonStyles:
  startScanColor: "#43A047"     # Start scan button color (default: #388E3C)
  addCheckpointColor: "#1E88E5" # Add checkpoint button (default: #1976D2)

Icon Customization

You can customize icons for modem, router, and location pin:

modemIcon:
  name: wifi_tethering  # Material icon name
  size: 26              # Icon size

routerIcon:
  name: router
  size: 26

locationPinIcon:
  name: place
  size: 48

Event Handlers

Event Description When Triggered
onMessage Display messages to user Various validation and status messages
onFirstCheckpoint First checkpoint added When user adds the very first checkpoint
onAllGridsFilled All grid cells scanned When heatmap is complete
getSignalStrength Custom signal measurement Deprecated - use signalValues property instead

Implementation Details

Signal Value Processing Flow

  1. Collection Phase:

    • Signal values are continuously collected and stored with timestamps
    • Values can come from any source (API, device sensor, mock data)
  2. Checkpoint Addition:

    • User taps "Add Checkpoint" at a physical location
    • Widget records current timestamp and location
  3. Path Segment Processing:

    • Widget retrieves all signal values between previous and current checkpoint timestamps
    • These values are distributed across grid cells along the path
    • If more values than cells: averaging is used
    • If more cells than values: values are distributed proportionally
    • If no values available: linear interpolation between checkpoint values is used
  4. Heatmap Update:

    • Grid cells are colored based on their assigned dBm values
    • Visual path line connects checkpoints
    • Scan point dots mark checkpoint locations

Grid Cell Protection

The widget implements smart grid cell management:

  • Once a cell is scanned and assigned a value, it's never overwritten
  • This prevents data loss when paths cross or overlap
  • Ensures the first measurement at each location is preserved

Performance Optimization

  • Grid Size Impact:

    • 12-16: Recommended for balanced detail and performance
    • 20+: High detail but slower on large floor plans
    • 4-8: Fast but low detail
  • Signal Value Buffering:

    • Values are stored in memory until checkpoint is added
    • Old values are retained for entire session
    • Consider clearing old values periodically for very long scanning sessions

New approach:

WiFiHeatmap:
  signalValues: ${ensemble.storage.dbmList}
  
  onFirstCheckpoint:
    startTimer:
      onTimer:
        executeCode:
          body: |-
            //@code
            ensemble.storage.dbmList.push({
              dbm: getCurrentSignalStrength(),
              timestamp: Date.now()
            });
            testHeatmap.signalValues = ensemble.storage.dbmList;

The new approach provides:

  • ✅ Continuous data collection
  • ✅ Timestamp-based accuracy
  • ✅ Better signal distribution along paths
  • ✅ Support for external data sources

Best Practices

  1. Start Timer on First Checkpoint: Don't waste resources polling for signal values before scanning starts
  2. Stop Timer When Complete: Use onAllGridsFilled to stop signal collection
  3. Use Appropriate Grid Size: Balance between detail (high gridSize) and performance (low gridSize)
  4. Provide Timestamps: Always include timestamps with signal values for accurate path-based distribution
  5. Handle API Errors: Implement error handling in your onResponse code
  6. Clear Old Data: For long sessions, consider clearing old signal values to prevent memory issues

Troubleshooting

Signal values not updating

  • Check that signalValues property is bound to a reactive variable
  • Verify the timer is actually running
  • Ensure timestamps are in milliseconds (not seconds)

Heatmap looks blocky

  • Increase gridSize for more detail
  • Ensure you're collecting enough signal values between checkpoints
  • Check that timer interval isn't too long (1 second is recommended)

Performance issues

  • Reduce gridSize if scanning is slow
  • Optimize API call frequency
  • Clear old signal values periodically

Grid cells not filling

  • Verify signal values have correct format ({dbm: number, timestamp: number})
  • Check that checkpoints are being added in different grid cells
  • Ensure signal values have timestamps between checkpoint times

Sample Video

sample.mp4

- Introduced separate style classes for devices, scan points, location pins, grids, heatmaps, paths, signals, and buttons.
- Removed the previous WiFiHeatmapTheme class and replaced it with individual style classes for better modularity and customization.
…ntegration

- Introduced Checkpoint model to track grid positions and timestamps.
- Added signalValues parameter to WiFiHeatmapWidget for external signal data.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant