Tap Into the Pacific Data Streamβ„’

Build Your Own Bob Dashboard with Live Ocean Telemetry

Welcome to the most democratized ocean data feed on the internet. While Bob battles Pacific swells, every sensor reading and GPS coordinate streams live through Redis and InfluxDB. This isn't just telemetryβ€”it's raw maritime adventure data from the middle of nowhere.

Why settle for boring dashboards when you can build something spectacular? Whether you're correlating wave heights with propeller efficiency, creating anxiety-inducing progress trackers, or just obsessing over real-time ocean data, these streams are your gateway to Bob's digital soul. Build AI mood predictors, whale encounter alerts, or the most beautiful ocean visualization the internet has ever seen.

This is citizen science at its finestβ€”a floating sensor platform funded by internet strangers, transmitting data that anyone can access and transform into something amazing. Bob's journey is your data playground.

πŸ—ΊοΈ Embed the Live Map

πŸ“ Embeddable Map Widget

Drop Bob's live tracking map directly into your own website or application. Clean, borderless design with real-time GPS updates from Redis. Perfect for news articles, dashboards, or any page that needs live ocean tracking.

Embed URL:
https://your-domain.com/?embed=true
https://your-domain.com/embed
HTML Example:
<iframe src="/?embed=true" width="100%" height="500" frameborder="0"></iframe>
🎯 View Live Demo & Documentation β†’

πŸ”Œ Live Data Streams

πŸ“Š Redis Real-Time Stream

Lightning-fast key-value store with Bob's current state. Perfect for real-time dashboards and live applications.

Connection Details:
Host: redis-17021.fcrce172.us-east-1-1.ec2.redns.redis-cloud.com
Port: 17021
Username: readonlyuser
Password: Trawlingforlikes1!!
Access: READ-ONLY
Complete Redis Key Reference:
🌍 GPS Subsystem (sensors:gps:*)
  • sensors:gps:current_lat - Current latitude (decimal degrees)
  • sensors:gps:current_lon - Current longitude (decimal degrees)
  • sensors:gps:velocity_knots - Speed over ground (knots)
  • sensors:gps:velocity_mps - Speed over ground (meters/second)
  • sensors:gps:altitude - GPS altitude (meters above sea level)
  • sensors:gps:satellites - Number of GPS satellites in view
  • sensors:gps:movement_heading - Course over ground (degrees)
  • sensors:gps:timestamp - Unix timestamp of GPS fix
  • sensors:gps:fix_quality - GPS fix quality indicator
  • sensors:gps:hdop - Horizontal dilution of precision
  • sensors:gps:geoid_height - Height of geoid above WGS84
  • sensors:gps:dgps_age - Age of DGPS corrections
🧭 Magnetometer & Navigation (sensors:mag:*, sensors:navigation:*)
  • sensors:mag:heading - Magnetic compass heading (degrees)
  • sensors:mag:raw_x - Raw magnetometer X-axis reading
  • sensors:mag:raw_y - Raw magnetometer Y-axis reading
  • sensors:mag:raw_z - Raw magnetometer Z-axis reading
  • sensors:mag:calibrated_x - Calibrated magnetometer X-axis
  • sensors:mag:calibrated_y - Calibrated magnetometer Y-axis
  • sensors:mag:calibrated_z - Calibrated magnetometer Z-axis
  • sensors:navigation:heading - Autopilot heading (degrees)
  • sensors:navigation:target_bearing - Bearing to next waypoint
  • sensors:navigation:distance_to_target - Distance to waypoint (km)
  • sensors:navigation:heading_error - PID heading error
  • sensors:navigation:mode - Navigation mode (auto/manual)
⚑ MPPT Solar Charge Controller (sensors:mppt:*)
  • sensors:mppt:battery_voltage - Battery voltage (V)
  • sensors:mppt:battery_current - Battery charge current (A)
  • sensors:mppt:battery_power - Battery charge power (W)
  • sensors:mppt:array_voltage - Solar array voltage (V)
  • sensors:mppt:array_current - Solar array current (A)
  • sensors:mppt:array_power - Solar array power (W)
  • sensors:mppt:array_voc - Array open circuit voltage
  • sensors:mppt:array_pmax - Array maximum power point
  • sensors:mppt:charge_state - Charge controller state
  • sensors:mppt:charge_state_mapped - Human-readable charge state
  • sensors:mppt:load_current - Load output current (A)
  • sensors:mppt:battery_temperature - Battery temperature (Β°C)
πŸš— Motor Drive System (sensors:odrive:*)
  • sensors:odrive:power - Motor electrical power consumption (W)
  • sensors:odrive:current_a - Motor phase A current (A)
  • sensors:odrive:current_b - Motor phase B current (A)
  • sensors:odrive:velocity - Motor shaft velocity (rev/s)
  • sensors:odrive:position - Motor shaft position (revolutions)
  • sensors:odrive:voltage_bus - DC bus voltage (V)
  • sensors:odrive:temperature - Motor driver temperature (Β°C)
  • sensors:odrive:error_code - Error status code
  • sensors:odrive:control_mode - Motor control mode
  • sensors:odrive:encoder_count - Encoder count
  • sensors:odrive:torque_target - Target torque command
  • sensors:odrive:efficiency - Motor efficiency percentage
πŸŽ›οΈ Stepper Motor & Rudder (sensors:stepper:*)
  • sensors:stepper:angle - Rudder angle (degrees)
  • sensors:stepper:position - Stepper motor position (steps)
  • sensors:stepper:target_angle - Target rudder angle
  • sensors:stepper:current - Stepper motor current (mA)
  • sensors:stepper:temperature - Stepper driver temperature
  • sensors:stepper:enabled - Motor enable status
  • sensors:stepper:homed - Homing status
  • sensors:stepper:steps_per_degree - Calibration factor
  • sensors:stepper:max_angle - Maximum rudder angle
  • sensors:stepper:min_angle - Minimum rudder angle
  • sensors:stepper:velocity - Stepper velocity (steps/s)
  • sensors:stepper:stall_detection - Stall guard status
πŸ’» System Health (sensors:system:*)
  • sensors:system:cpu_usage - CPU utilization percentage
  • sensors:system:cpu_temperature - CPU temperature (Β°C)
  • sensors:system:memory_usage - RAM usage percentage
  • sensors:system:disk_usage - Storage usage percentage
  • sensors:system:uptime - System uptime (seconds)
  • sensors:system:boot_time - Last boot timestamp
  • sensors:system:network_rx - Network bytes received
  • sensors:system:network_tx - Network bytes transmitted
  • sensors:system:load_1min - 1-minute load average
  • sensors:system:load_5min - 5-minute load average
  • sensors:system:voltage_3v3 - 3.3V rail voltage
  • sensors:system:voltage_5v - 5V rail voltage
πŸ”Œ Power Management (sensors:power:*)
  • sensors:power:load_motor:value - Motor power switch state
  • sensors:power:load_stepper:value - Stepper power switch state
  • sensors:power:load_sensors:value - Sensor power switch state
  • sensors:power:load_comms:value - Communications power state
  • sensors:power:usb_frontcam1:value - Front camera 1 USB power
  • sensors:power:usb_frontcam2:value - Front camera 2 USB power
  • sensors:power:total_consumption - Total power consumption (W)
  • sensors:power:battery_capacity - Estimated battery capacity (%)
  • sensors:power:time_to_empty - Estimated battery runtime (hours)
  • sensors:power:charging_efficiency - Solar charging efficiency
  • sensors:power:power_balance - Net power (generation - consumption)
  • sensors:power:emergency_mode - Low power mode status
Complete Bob Redis Viewer (Python):
#!/usr/bin/env python3
"""
Project Bob - Comprehensive Redis Data Viewer

This script connects to Project Bob's public Redis data stream and displays a
comprehensive overview of the vessel's telemetry, organized by subsystem.

- Connects to the Redis cloud instance with read-only credentials.
- Fetches data from multiple subsystems: GPS, Navigation, Power, System, etc.
- Displays the data in a clean, formatted, and continuously updating table.
- Handles connection errors and missing data gracefully.
"""
import redis
import time
import os
from datetime import datetime

# --- Configuration ---
REDIS_HOST = 'redis-17021.fcrce172.us-east-1-1.ec2.redns.redis-cloud.com'
REDIS_PORT = 17021
REDIS_USERNAME = 'readonlyuser'
REDIS_PASSWORD = 'Trawlingforlikes1!!'

# --- Key Groups ---
# Define the Redis keys we want to monitor, grouped by subsystem
KEY_GROUPS = {
    "🚒  Vessel Status": {
        "Position": "sensors:gps:current_lat",
        "Heading": "sensors:navigation:heading",
        "Speed (knots)": "sensors:gps:velocity_knots",
        "Mode": "sensors:navigation:mode"
    },
    "🌍 GPS System": {
        "Latitude": "sensors:gps:current_lat",
        "Longitude": "sensors:gps:current_lon",
        "Satellites": "sensors:gps:satellites",
        "Altitude (m)": "sensors:gps:altitude",
        "Fix Quality": "sensors:gps:fix_quality"
    },
    "⚑ Power System": {
        "Battery (V)": "sensors:mppt:battery_voltage",
        "Solar Panel (W)": "sensors:mppt:array_power",
        "Motor Power (W)": "sensors:odrive:power",
        "Charge State": "sensors:mppt:charge_state_mapped"
    },
    "🧭 Navigation & Control": {
        "Compass Heading": "sensors:mag:heading",
        "Rudder Angle (Β°)": "sensors:stepper:angle",
        "Target Bearing": "sensors:navigation:target_bearing",
        "Distance to Target (km)": "sensors:navigation:distance_to_target"
    },
}

def connect_to_redis():
    """Establishes a connection to the Redis server."""
    print("🌊 Connecting to Bob's Redis data stream...")
    try:
        r = redis.Redis(
            host=REDIS_HOST,
            port=REDIS_PORT,
            username=REDIS_USERNAME,
            password=REDIS_PASSWORD,
            decode_responses=True,
            socket_connect_timeout=5,
            socket_timeout=5
        )
        r.ping()
        print("βœ… Connection successful!")
        return r
    except redis.exceptions.AuthenticationError:
        print("❌ Authentication failed. Check username and password.")
        return None
    except redis.exceptions.ConnectionError as e:
        print(f"❌ Connection error: {e}")
        return None
    except Exception as e:
        print(f"❌ An unexpected error occurred: {e}")
        return None

def fetch_data(redis_client, keys_to_fetch):
    """Fetches a batch of keys from Redis using a pipeline."""
    pipe = redis_client.pipeline()
    for key in keys_to_fetch:
        pipe.get(key)
    try:
        values = pipe.execute()
        return values
    except redis.exceptions.ConnectionError:
        print("⚠️ Lost connection to Redis. Attempting to reconnect...")
        return None
    except Exception as e:
        print(f"⚠️ Error during data fetch: {e}")
        return None

def display_data(data):
    """Clears the screen and displays the fetched data in a structured format."""
    os.system('cls' if os.name == 'nt' else 'clear')
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    print("=" * 60)
    print(f"  PROJECT BOB - LIVE TELEMETRY  |  {timestamp}")
    print("=" * 60)

    for group_name, keys in KEY_GROUPS.items():
        print(f"\n{group_name}")
        print("-" * 25)
        for name, key in keys.items():
            value = data.get(key, "N/A")
            # Try to format numbers nicely, otherwise display as is
            try:
                value_str = f"{float(value):.2f}"
            except (ValueError, TypeError):
                value_str = str(value) if value is not None else "N/A"
            print(f"  {name:<25}: {value_str}")
    
    print("\n" + "=" * 60)
    print("Press Ctrl+C to exit. Updating every 5 seconds...")

def main():
    """Main loop to connect, fetch, and display data."""
    redis_client = connect_to_redis()
    if not redis_client:
        return

    all_keys = [key for group in KEY_GROUPS.values() for key in group.values()]
    unique_keys = sorted(list(set(all_keys)))

    try:
        while True:
            values = fetch_data(redis_client, unique_keys)

            if values is not None:
                data_dict = dict(zip(unique_keys, values))
                display_data(data_dict)
            else:
                # Attempt to reconnect if fetch failed
                redis_client = connect_to_redis()
                if not redis_client:
                    print("Could not re-establish connection. Exiting.")
                    break
                time.sleep(5) # Wait before retrying after reconnect
                continue

            time.sleep(5)
    except KeyboardInterrupt:
        print("\n\nπŸ‘‹ Exiting Bob's telemetry viewer. Safe travels!")
    except Exception as e:
        print(f"\nAn unexpected error occurred in the main loop: {e}")

if __name__ == '__main__':
    main()
Installation & Setup:
# Install required packages
pip install redis

πŸ“ˆ InfluxDB Time Series

Historical data paradise. Every measurement Bob has ever taken, perfectly timestamped and ready for analysis.

Connection Details:
Host: https://us-east-1-1.aws.cloud2.influxdata.com
Organization: bob
Database: bob-telemetry
Token: RRp6hGho7p5rxi_BEUJzQcFdks6jWHSxHeW7ja21T0HR8lDXBLsvxPze93CmJnB5X_sl1qdya8CxdGnuOk3Jxg==
Access: READ-ONLY
Complete InfluxDB Measurement Reference:
🌍 GPS Measurements (measurement: "gps")
  • current_lat - Current latitude (float, degrees)
  • current_lon - Current longitude (float, degrees)
  • velocity_knots - Speed over ground (float, knots)
  • velocity_mps - Speed over ground (float, m/s)
  • altitude - GPS altitude (float, meters MSL)
  • satellites - Satellite count (integer)
  • movement_heading - Course over ground (float, degrees)
  • fix_quality - GPS fix quality (integer, 0-8)
  • hdop - Horizontal dilution of precision (float)
  • geoid_height - Geoid height above WGS84 (float, meters)
  • dgps_age - Age of DGPS corrections (float, seconds)
  • timestamp_gps - GPS receiver timestamp (integer, unix)
🧭 Navigation & Control (measurement: "navigation")
  • heading - Autopilot heading (float, degrees)
  • target_bearing - Bearing to next waypoint (float, degrees)
  • distance_to_target - Distance to waypoint (float, km)
  • heading_error - PID heading error (float, degrees)
  • pid_p_term - PID proportional term (float)
  • pid_i_term - PID integral term (float)
  • pid_d_term - PID derivative term (float)
  • pid_total_output - Total PID output (float)
  • integral_value - PID integral accumulator (float)
  • integral_limit - PID integral windup limit (float)
  • mode - Navigation mode (string: auto/manual)
  • power_save - Power save mode (boolean)
⚑ MPPT Solar System (measurement: "mppt")
  • battery_voltage - Battery voltage (float, V)
  • battery_current - Battery charge current (float, A)
  • battery_power - Battery charge power (float, W)
  • array_voltage - Solar array voltage (float, V)
  • array_current - Solar array current (float, A)
  • array_power - Solar array power (float, W)
  • array_voc - Array open circuit voltage (float, V)
  • array_pmax - Maximum power point (float, W)
  • charge_state - Charge state code (integer)
  • charge_state_mapped - Charge state (string)
  • load_current - Load output current (float, A)
  • battery_temperature - Battery temp (float, Β°C)
🧭 Magnetometer (measurement: "magnetometer")
  • heading - Magnetic compass heading (float, degrees)
  • raw_x - Raw magnetometer X-axis (float, Β΅T)
  • raw_y - Raw magnetometer Y-axis (float, Β΅T)
  • raw_z - Raw magnetometer Z-axis (float, Β΅T)
  • calibrated_x - Calibrated X-axis (float, Β΅T)
  • calibrated_y - Calibrated Y-axis (float, Β΅T)
  • calibrated_z - Calibrated Z-axis (float, Β΅T)
  • magnitude - Total field strength (float, Β΅T)
  • declination - Magnetic declination (float, degrees)
  • inclination - Magnetic inclination (float, degrees)
  • calibration_offset_x - X calibration offset (float)
  • calibration_offset_y - Y calibration offset (float)
πŸš— Motor Drive (measurement: "odrive")
  • power - Electrical power consumption (float, W)
  • current_a - Motor phase A current (float, A)
  • current_b - Motor phase B current (float, A)
  • velocity - Motor shaft velocity (float, rev/s)
  • position - Motor shaft position (float, revolutions)
  • voltage_bus - DC bus voltage (float, V)
  • temperature - Motor driver temperature (float, Β°C)
  • error_code - Error status code (integer)
  • control_mode - Motor control mode (integer)
  • encoder_count - Encoder position (integer, counts)
  • torque_target - Target torque command (float, Nm)
  • efficiency - Motor efficiency (float, percentage)
πŸŽ›οΈ Stepper & Rudder (measurement: "stepper")
  • angle - Rudder angle (float, degrees)
  • position - Stepper position (integer, steps)
  • target_angle - Target rudder angle (float, degrees)
  • current - Stepper motor current (float, mA)
  • temperature - Stepper driver temp (float, Β°C)
  • enabled - Motor enable status (boolean)
  • homed - Homing completion status (boolean)
  • steps_per_degree - Calibration factor (float)
  • max_angle - Maximum rudder angle (float, degrees)
  • min_angle - Minimum rudder angle (float, degrees)
  • velocity - Stepper velocity (float, steps/s)
  • stall_detection - Stall guard status (boolean)
πŸ’» System Health (measurement: "system")
  • cpu_usage - CPU utilization (float, percentage)
  • cpu_temperature - CPU temperature (float, Β°C)
  • memory_usage - RAM usage (float, percentage)
  • disk_usage - Storage usage (float, percentage)
  • uptime - System uptime (integer, seconds)
  • boot_time - Last boot timestamp (integer, unix)
  • network_rx_bytes - Network RX bytes (integer)
  • network_tx_bytes - Network TX bytes (integer)
  • load_1min - 1-minute load average (float)
  • load_5min - 5-minute load average (float)
  • voltage_3v3 - 3.3V rail voltage (float, V)
  • voltage_5v - 5V rail voltage (float, V)
🌊 Environmental (measurement: "environment")
  • air_temperature - Air temperature (float, Β°C)
  • water_temperature - Water temperature (float, Β°C)
  • humidity - Relative humidity (float, percentage)
  • pressure - Atmospheric pressure (float, hPa)
  • wave_height - Estimated wave height (float, meters)
  • wind_speed - Wind speed (float, knots)
  • wind_direction - Wind direction (float, degrees)
  • uv_index - UV radiation index (float)
  • light_intensity - Ambient light (float, lux)
  • precipitation - Rainfall rate (float, mm/hr)
  • salinity - Water salinity (float, PSU)
  • turbidity - Water turbidity (float, NTU)
Data Retention & Update Frequency:
  • πŸ“Š High-resolution data: 30 days full resolution
  • πŸ“ˆ Downsampled data: Complete journey archive (5min avg)
  • πŸ”„ Update frequency: Every 5 seconds (real-time)
  • πŸ“¦ Batch size: Up to 10,000 records per query
  • ⏱️ Query timeout: 30 seconds maximum
  • πŸ“ Field types: float64, integer, string, boolean
Complete InfluxDB Data Analyzer (Python):
#!/usr/bin/env python3
"""
Bob's Historical Data Analyzer
Pulls complete InfluxDB telemetry into pandas DataFrame every 30 seconds
Analyzes Bob's journey patterns, performance metrics, and ocean conditions
"""
import pandas as pd
import time
from datetime import datetime, timedelta
from influxdb_client_3 import InfluxDBClient3

def connect_to_influx():
    """Connect to Bob's InfluxDB historical data store"""
    print("πŸ“Š Connecting to Bob's InfluxDB time series database...")
    
    try:
        # InfluxDB connection parameters
        token = "RRp6hGho7p5rxi_BEUJzQcFdks6jWHSxHeW7ja21T0HR8lDXBLsvxPze93CmJnB5X_sl1qdya8CxdGnuOk3Jxg=="
        org = "bob"
        host = "https://us-east-1-1.aws.cloud2.influxdata.com"
        database = "bob-telemetry"
        
        # Create InfluxDB client connection
        client = InfluxDBClient3(host=host, token=token, org=org)
        
        print("βœ… Connected to Bob's historical database!")
        return client, database
        
    except Exception as e:
        print(f"❌ InfluxDB connection failed: {e}")
        return None, None

def fetch_complete_telemetry(client, database, hours_back=24):
    """Fetch comprehensive telemetry data from InfluxDB"""
    print(f"πŸ” Fetching last {hours_back} hours of Bob's complete telemetry...")
    
    try:
        # Comprehensive SQL query to get all major telemetry streams
        # This pulls GPS, power, navigation, and environmental data
        query = f'''
        SELECT 
            time,
            -- GPS & Navigation Data
            gps_lat as latitude,
            gps_lon as longitude,
            gps_velocity_knots as speed_knots,
            gps_satellites,
            navigation_heading as compass_heading,
            navigation_mode,
            
            -- Power & Energy Systems
            battery_voltage,
            solar_power_watts,
            motor_power_watts,
            power_consumption_total,
            
            -- Environmental Conditions  
            air_temperature_c,
            water_temperature_c,
            wave_height_meters,
            wind_speed_knots,
            wind_direction,
            
            -- System Health
            cpu_temperature,
            system_uptime_hours,
            memory_usage_percent,
            storage_usage_percent
            
        FROM "{database}"."autogen"."telemetry"
        WHERE time >= now() - interval '{hours_back} hours'
        ORDER BY time DESC
        LIMIT 10000
        '''
        
        # Execute query and convert to pandas DataFrame
        print("⏳ Executing query...")
        table = client.query(query=query, database=database, language='sql')
        df = table.to_pandas()
        
        # Convert time column to datetime if it's not already
        if 'time' in df.columns:
            df['time'] = pd.to_datetime(df['time'])
            df.set_index('time', inplace=True)
        
        print(f"βœ… Retrieved {len(df)} telemetry records!")
        return df
        
    except Exception as e:
        print(f"❌ Error fetching telemetry: {e}")
        # Fallback to simplified GPS-only query if comprehensive query fails
        try:
            print("πŸ”„ Trying simplified GPS query...")
            simple_query = f'''
            SELECT time, current_lat, current_lon, velocity_knots, satellites
            FROM "{database}"."autogen"."gps" 
            WHERE time >= now() - interval '{hours_back} hours'
            ORDER BY time DESC
            LIMIT 5000
            '''
            
            table = client.query(query=simple_query, database=database, language='sql')
            df = table.to_pandas()
            
            if 'time' in df.columns:
                df['time'] = pd.to_datetime(df['time'])
                df.set_index('time', inplace=True)
                
            print(f"βœ… Retrieved {len(df)} GPS records (simplified mode)")
            return df
            
        except Exception as e2:
            print(f"❌ Simplified query also failed: {e2}")
            return None

def analyze_telemetry(df):
    """Analyze Bob's telemetry data and print insights"""
    if df is None or df.empty:
        print("⚠️ No data to analyze")
        return
    
    print("\n" + "="*80)
    print("πŸ“ˆ BOB'S TELEMETRY ANALYSIS")
    print("="*80)
    
    # Basic dataset info
    print(f"πŸ“Š Dataset Overview:")
    print(f"   β€’ Time Range: {df.index.min()} to {df.index.max()}")
    print(f"   β€’ Total Records: {len(df):,}")
    print(f"   β€’ Data Points: {len(df.columns)} metrics")
    print(f"   β€’ Duration: {(df.index.max() - df.index.min()).total_seconds()/3600:.1f} hours")
    
    # GPS Analysis (if available)
    if 'latitude' in df.columns or 'current_lat' in df.columns:
        lat_col = 'latitude' if 'latitude' in df.columns else 'current_lat'
        lon_col = 'longitude' if 'longitude' in df.columns else 'current_lon'
        
        print(f"\n🌍 GPS Position Analysis:")
        print(f"   β€’ Current Position: {df[lat_col].iloc[0]:.6f}Β°, {df[lon_col].iloc[0]:.6f}Β°")
        print(f"   β€’ Position Range: {df[lat_col].min():.4f}Β° to {df[lat_col].max():.4f}Β° latitude")
        print(f"   β€’ Distance Span: ~{abs(df[lat_col].max() - df[lat_col].min()) * 69:.1f} miles N-S")
    
    # Speed Analysis
    speed_col = None
    for col in ['speed_knots', 'velocity_knots']:
        if col in df.columns:
            speed_col = col
            break
            
    if speed_col:
        print(f"\nπŸƒ Speed Analysis:")
        print(f"   β€’ Current Speed: {df[speed_col].iloc[0]:.2f} knots")
        print(f"   β€’ Average Speed: {df[speed_col].mean():.2f} knots")
        print(f"   β€’ Max Speed: {df[speed_col].max():.2f} knots")
        print(f"   β€’ Speed Std Dev: {df[speed_col].std():.2f} knots")
    
    # Power Analysis (if available)
    if 'battery_voltage' in df.columns:
        print(f"\nπŸ”‹ Power System Analysis:")
        print(f"   β€’ Current Battery: {df['battery_voltage'].iloc[0]:.2f}V")
        print(f"   β€’ Battery Range: {df['battery_voltage'].min():.2f}V - {df['battery_voltage'].max():.2f}V")
        if 'solar_power_watts' in df.columns:
            print(f"   β€’ Avg Solar Power: {df['solar_power_watts'].mean():.1f}W")
    
    # Data Quality Assessment
    print(f"\nπŸ“Š Data Quality:")
    missing_data = df.isnull().sum()
    total_possible = len(df) * len(df.columns)
    missing_percent = (missing_data.sum() / total_possible) * 100
    print(f"   β€’ Data Completeness: {100-missing_percent:.1f}%")
    print(f"   β€’ Missing Values: {missing_data.sum():,} out of {total_possible:,}")
    
    # Show recent data sample
    print(f"\nπŸ“‹ Most Recent Data (last 5 records):")
    print(df.head().to_string())

def main():
    """Main analysis loop - fetches and analyzes data every 30 seconds"""
    # Connect to InfluxDB
    client, database = connect_to_influx()
    if not client:
        return
    
    print("πŸ”„ Starting continuous telemetry analysis... (Press Ctrl+C to stop)")
    print("πŸ“… Data will refresh every 30 seconds")
    
    try:
        while True:
            # Get current timestamp
            timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            print(f"\nπŸ• [{timestamp}] Fetching latest telemetry data...")
            
            # Fetch comprehensive telemetry data
            df = fetch_complete_telemetry(client, database, hours_back=24)
            
            # Analyze the data
            analyze_telemetry(df)
            
            # Optional: Save data to CSV for further analysis
            if df is not None and not df.empty:
                filename = f"bob_telemetry_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
                df.to_csv(filename)
                print(f"\nπŸ’Ύ Data saved to: {filename}")
            
            print(f"\n⏱️  Waiting 30 seconds for next update...")
            print("-" * 80)
            
            # Wait 30 seconds before next analysis
            time.sleep(30)
            
    except KeyboardInterrupt:
        print(f"\nπŸ‘‹ Analysis stopped. Bob's data lives on!")
        print("πŸ“ Check your directory for saved CSV files with Bob's telemetry data.")

# Run the analyzer
if __name__ == '__main__':
    main()
Installation & Setup:
# Install required packages
pip install influxdb-client-3 pandas

πŸš€ Build Something Amazing

We can't wait to see what you create with Bob's data. Whether it's a beautiful visualization, a predictive model, or something completely unexpected, tag us when you ship it. The best community-built tools might just get featured on the main dashboard.

Remember: Bob's success depends on this data flowing freely. Build tools that help us understand his journey, predict his challenges, and celebrate his victories. The ocean is vast, but together we can make sense of every wave.