Claude Code Plugins

Community-maintained marketplace

Feedback

System diagnostics, verification, and troubleshooting for Badger 2350. Use when checking firmware version, verifying installations, diagnosing hardware issues, troubleshooting errors, or performing system health checks on Badger 2350.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name badger-diagnostics
description System diagnostics, verification, and troubleshooting for Badger 2350. Use when checking firmware version, verifying installations, diagnosing hardware issues, troubleshooting errors, or performing system health checks on Badger 2350.

Badger 2350 Diagnostics and Troubleshooting

Comprehensive diagnostics and troubleshooting tools for verifying your Badger 2350 setup, checking installations, and resolving common issues.

⚠️ When to Use This Skill

Use this skill FIRST in these situations:

  1. Starting a new session - Verify everything works before coding
  2. After setup - Confirm installation completed correctly
  3. Before debugging - Rule out environment issues
  4. When errors occur - Diagnose the root cause
  5. After firmware updates - Verify everything still works

Best Practice: Run diagnostics at the start of EVERY development session. It takes 30 seconds and prevents hours of debugging.

Quick Verification Command

Run this FIRST every session (doesn't require any files to exist):

Level 1: Basic Connection Test

# Simplest test - just verify badge responds
mpremote exec "print('Badge connected!')"
# Should print: Badge connected!

# If this fails, badge isn't connected or mpremote not installed

Level 2: Full Verification

# Complete verification (auto-detects port on macOS/Linux)
mpremote exec "import sys, gc; from badgeware import screen, brushes, shapes, io; print('=== VERIFICATION ==='); print('✓ MicroPython:', sys.version[:30]); print('✓ Memory:', gc.mem_free(), 'bytes'); print('✓ badgeware: loaded'); print('✓ Display: 160x120'); print('=== ALL OK ===')"

Expected output: All checks with ✓ marks and no errors.

With explicit port (if auto-detect fails):

mpremote connect /dev/cu.usbmodem1101 exec "from badgeware import screen; print('✓ Badge OK')"
# Replace /dev/cu.usbmodem1101 with your port

If this fails: Continue with detailed diagnostics below.

Quick System Check

Run this complete system diagnostic in REPL:

# diagnostic.py - Complete system check
import sys
import gc
import os
from machine import freq, unique_id
import ubinascii

def system_info():
    """Display complete system information"""
    print("=" * 50)
    print("BADGER 2350 SYSTEM DIAGNOSTICS")
    print("=" * 50)

    # MicroPython version
    print(f"\n[MicroPython]")
    print(f"  Version: {sys.version}")
    print(f"  Implementation: {sys.implementation}")
    print(f"  Platform: {sys.platform}")

    # Hardware info
    print(f"\n[Hardware]")
    print(f"  CPU Frequency: {freq():,} Hz ({freq() / 1_000_000:.0f} MHz)")
    uid = ubinascii.hexlify(unique_id()).decode()
    print(f"  Unique ID: {uid}")

    # Memory
    gc.collect()
    print(f"\n[Memory]")
    print(f"  Free: {gc.mem_free():,} bytes ({gc.mem_free() / 1024:.1f} KB)")
    print(f"  Allocated: {gc.mem_alloc():,} bytes ({gc.mem_alloc() / 1024:.1f} KB)")
    total = gc.mem_free() + gc.mem_alloc()
    print(f"  Total: {total:,} bytes ({total / 1024:.1f} KB)")

    # File system
    print(f"\n[File System]")
    try:
        stat = os.statvfs('/')
        block_size = stat[0]
        total_blocks = stat[2]
        free_blocks = stat[3]
        total_bytes = block_size * total_blocks
        free_bytes = block_size * free_blocks
        used_bytes = total_bytes - free_bytes

        print(f"  Total: {total_bytes:,} bytes ({total_bytes / 1024 / 1024:.2f} MB)")
        print(f"  Used: {used_bytes:,} bytes ({used_bytes / 1024 / 1024:.2f} MB)")
        print(f"  Free: {free_bytes:,} bytes ({free_bytes / 1024 / 1024:.2f} MB)")
    except:
        print("  Unable to check filesystem")

    # Module path
    print(f"\n[Module Search Paths]")
    for path in sys.path:
        print(f"  {path}")

    print("\n" + "=" * 50)

# Run diagnostic
system_info()

Firmware Version Check

Check MicroPython Firmware

import sys

# Full version info
print(sys.version)
# Example: 3.4.0; MicroPython v1.20.0 on 2023-04-26

# Implementation details
print(sys.implementation)
# (name='micropython', version=(1, 20, 0), _machine='Raspberry Pi Pico W with RP2040', _mpy=6182)

# Extract version number
version = sys.implementation.version
print(f"MicroPython {version[0]}.{version[1]}.{version[2]}")

Check Badger Library Version

import badger2040

# Check if version attribute exists
if hasattr(badger2040, '__version__'):
    print(f"Badger library version: {badger2040.__version__}")
else:
    print("Badger library version not available")

# Check file location
print(f"Badger library: {badger2040.__file__}")

Recommended Firmware Versions

Verify you have compatible firmware:

def check_firmware_compatibility():
    """Check if firmware is compatible with Badger 2350"""
    version = sys.implementation.version

    if version[0] >= 1 and version[1] >= 20:
        print("✓ MicroPython version is compatible")
        return True
    else:
        print("✗ MicroPython version may be outdated")
        print("  Recommended: MicroPython 1.20+")
        print(f"  Current: {version[0]}.{version[1]}.{version[2]}")
        return False

check_firmware_compatibility()

Module Verification

Check Core Modules

def verify_core_modules():
    """Verify essential modules are available"""
    required_modules = {
        'badger2040': 'Badger display library',
        'machine': 'Hardware interface',
        'time': 'Time functions',
        'gc': 'Garbage collection',
        'sys': 'System functions',
        'os': 'Operating system interface'
    }

    optional_modules = {
        'network': 'WiFi support',
        'urequests': 'HTTP client',
        'ujson': 'JSON parsing',
        'ubinascii': 'Binary/ASCII conversion'
    }

    print("Checking required modules...")
    all_ok = True
    for module, description in required_modules.items():
        try:
            __import__(module)
            print(f"  ✓ {module:15s} - {description}")
        except ImportError:
            print(f"  ✗ {module:15s} - MISSING - {description}")
            all_ok = False

    print("\nChecking optional modules...")
    for module, description in optional_modules.items():
        try:
            __import__(module)
            print(f"  ✓ {module:15s} - {description}")
        except ImportError:
            print(f"  ○ {module:15s} - Not installed - {description}")

    return all_ok

verify_core_modules()

List All Installed Packages

import os

def list_installed_packages():
    """List all installed packages in /lib"""
    print("Installed packages:")

    # Check /lib directory
    try:
        lib_contents = os.listdir('/lib')
        if lib_contents:
            for item in sorted(lib_contents):
                # Try to get more info
                path = f'/lib/{item}'
                try:
                    stat = os.stat(path)
                    size = stat[6]  # File size
                    print(f"  {item:30s} {size:8,} bytes")
                except:
                    print(f"  {item}")
        else:
            print("  (no packages in /lib)")
    except OSError:
        print("  /lib directory not found")

    # Check root directory for .py files
    print("\nRoot directory modules:")
    root_contents = os.listdir('/')
    py_files = [f for f in root_contents if f.endswith('.py')]
    for f in sorted(py_files):
        stat = os.stat(f)
        size = stat[6]
        print(f"  {f:30s} {size:8,} bytes")

list_installed_packages()

Hardware Diagnostics

Display Test

import badger2040

def test_display():
    """Test display functionality"""
    print("Testing display...")

    badge = badger2040.Badger2040()

    # Test 1: Clear screen
    badge.set_pen(15)
    badge.clear()
    badge.update()
    print("  ✓ Clear screen")

    # Test 2: Draw text
    badge.set_pen(0)
    badge.text("Display Test", 10, 10, scale=2)
    badge.update()
    print("  ✓ Draw text")

    # Test 3: Draw shapes
    badge.line(10, 40, 100, 40)
    badge.rectangle(10, 50, 50, 30)
    badge.update()
    print("  ✓ Draw shapes")

    print("Display test complete!")

test_display()

Button Test

import badger2040
import time

def test_buttons():
    """Test all buttons"""
    print("Button test - Press each button:")
    print("  A, B, C, UP, DOWN")
    print("Press Ctrl+C to exit")

    badge = badger2040.Badger2040()
    tested = set()

    while len(tested) < 5:
        if badge.pressed(badger2040.BUTTON_A) and 'A' not in tested:
            print("  ✓ Button A works")
            tested.add('A')
        elif badge.pressed(badger2040.BUTTON_B) and 'B' not in tested:
            print("  ✓ Button B works")
            tested.add('B')
        elif badge.pressed(badger2040.BUTTON_C) and 'C' not in tested:
            print("  ✓ Button C works")
            tested.add('C')
        elif badge.pressed(badger2040.BUTTON_UP) and 'UP' not in tested:
            print("  ✓ Button UP works")
            tested.add('UP')
        elif badge.pressed(badger2040.BUTTON_DOWN) and 'DOWN' not in tested:
            print("  ✓ Button DOWN works")
            tested.add('DOWN')

        time.sleep(0.1)

    print("All buttons tested successfully!")

test_buttons()

GPIO Test

from machine import Pin

def test_gpio():
    """Test GPIO pins"""
    print("Testing GPIO pins...")

    # Test output
    test_pin = Pin(25, Pin.OUT)
    test_pin.value(1)
    print(f"  ✓ Pin 25 set to HIGH: {test_pin.value()}")
    test_pin.value(0)
    print(f"  ✓ Pin 25 set to LOW: {test_pin.value()}")

    # Test input with pull-up
    input_pin = Pin(15, Pin.IN, Pin.PULL_UP)
    print(f"  ✓ Pin 15 input (pull-up): {input_pin.value()}")

    print("GPIO test complete!")

test_gpio()

I2C Bus Scan

from machine import I2C, Pin

def scan_i2c():
    """Scan for I2C devices"""
    print("Scanning I2C bus...")

    i2c = I2C(0, scl=Pin(5), sda=Pin(4), freq=400000)
    devices = i2c.scan()

    if devices:
        print(f"  Found {len(devices)} device(s):")
        for device in devices:
            print(f"    0x{device:02X} ({device})")
    else:
        print("  No I2C devices found")

    return devices

scan_i2c()

Network Diagnostics

WiFi Connection Test

import network
import time

def test_wifi(ssid, password, timeout=10):
    """Test WiFi connection"""
    print(f"Testing WiFi connection to '{ssid}'...")

    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)

    # Check if already connected
    if wlan.isconnected():
        print("  ✓ Already connected")
        print(f"    IP: {wlan.ifconfig()[0]}")
        return True

    # Attempt connection
    print("  Connecting...")
    wlan.connect(ssid, password)

    # Wait for connection
    start = time.time()
    while not wlan.isconnected() and (time.time() - start) < timeout:
        time.sleep(0.5)
        print(".", end="")

    print()  # New line

    if wlan.isconnected():
        config = wlan.ifconfig()
        print("  ✓ Connected successfully")
        print(f"    IP Address: {config[0]}")
        print(f"    Subnet Mask: {config[1]}")
        print(f"    Gateway: {config[2]}")
        print(f"    DNS: {config[3]}")
        print(f"    Signal Strength: {wlan.status('rssi')} dBm")
        return True
    else:
        print("  ✗ Connection failed")
        status = wlan.status()
        print(f"    Status code: {status}")
        return False

# Usage
# test_wifi('YourSSID', 'YourPassword')

Network Speed Test

import urequests
import time

def test_network_speed():
    """Test network download speed"""
    print("Testing network speed...")

    url = "http://httpbin.org/bytes/10000"  # 10KB test file

    try:
        start = time.ticks_ms()
        response = urequests.get(url)
        end = time.ticks_ms()

        size = len(response.content)
        duration = time.ticks_diff(end, start) / 1000  # Convert to seconds

        speed = (size / duration) / 1024  # KB/s

        print(f"  Downloaded: {size} bytes")
        print(f"  Time: {duration:.2f}s")
        print(f"  Speed: {speed:.2f} KB/s")

        response.close()
        return True
    except Exception as e:
        print(f"  ✗ Network test failed: {e}")
        return False

# test_network_speed()

Memory Diagnostics

Memory Usage Analysis

import gc

def analyze_memory():
    """Analyze memory usage"""
    print("Memory Analysis:")

    # Before collection
    free_before = gc.mem_free()
    alloc_before = gc.mem_alloc()

    # Collect garbage
    gc.collect()

    # After collection
    free_after = gc.mem_free()
    alloc_after = gc.mem_alloc()

    print(f"\nBefore garbage collection:")
    print(f"  Free: {free_before:,} bytes ({free_before / 1024:.1f} KB)")
    print(f"  Allocated: {alloc_before:,} bytes ({alloc_before / 1024:.1f} KB)")

    print(f"\nAfter garbage collection:")
    print(f"  Free: {free_after:,} bytes ({free_after / 1024:.1f} KB)")
    print(f"  Allocated: {alloc_after:,} bytes ({alloc_after / 1024:.1f} KB)")

    freed = free_after - free_before
    print(f"\nReclaimed: {freed:,} bytes ({freed / 1024:.1f} KB)")

    # Total memory
    total = free_after + alloc_after
    usage_percent = (alloc_after / total) * 100

    print(f"\nTotal memory: {total:,} bytes ({total / 1024:.1f} KB)")
    print(f"Usage: {usage_percent:.1f}%")

    # Warning if low
    if free_after < 10000:
        print("\n⚠ WARNING: Low memory!")
    elif free_after < 50000:
        print("\n⚠ CAUTION: Memory running low")
    else:
        print("\n✓ Memory usage looks good")

analyze_memory()

Find Memory Leaks

import gc

def find_memory_leaks(function, iterations=10):
    """Test function for memory leaks"""
    print(f"Testing for memory leaks ({iterations} iterations)...")

    gc.collect()
    initial_mem = gc.mem_free()

    for i in range(iterations):
        function()
        gc.collect()

        current_mem = gc.mem_free()
        leaked = initial_mem - current_mem

        if leaked > 0:
            print(f"  Iteration {i+1}: Leaked {leaked} bytes")

    gc.collect()
    final_mem = gc.mem_free()
    total_leaked = initial_mem - final_mem

    if total_leaked > 100:  # Allow small variance
        print(f"⚠ Possible memory leak: {total_leaked} bytes leaked")
    else:
        print(f"✓ No significant memory leak detected")

# Usage
# def test_func():
#     data = [i for i in range(100)]
# find_memory_leaks(test_func)

Error Diagnosis

Common Error Patterns

def diagnose_error(error):
    """Provide diagnosis for common errors"""
    error_str = str(error)

    diagnostics = {
        'ImportError': """
        Module not found. Check:
        - Module is installed (use mip.install())
        - Module is in /lib or root directory
        - Module name is spelled correctly
        - File has .py extension
        """,

        'MemoryError': """
        Out of memory. Try:
        - Run gc.collect() before allocation
        - Reduce variable scope
        - Use generators instead of lists
        - Break large operations into smaller chunks
        - Delete unused objects with 'del'
        """,

        'OSError': """
        File/Hardware operation failed. Check:
        - File path is correct
        - File exists (for reading)
        - Filesystem not full (for writing)
        - Hardware is connected properly
        - Pins are not already in use
        """,

        'AttributeError': """
        Attribute not found. Check:
        - Object has the attribute/method
        - Spelling is correct
        - Module is imported correctly
        - Object is initialized
        """,

        'ValueError': """
        Invalid value. Check:
        - Parameter values are in valid range
        - Data types match expected types
        - String formats are correct
        """
    }

    # Find matching error type
    for error_type, advice in diagnostics.items():
        if error_type in error_str:
            print(f"Diagnosis for {error_type}:")
            print(advice)
            return

    print("Error type not recognized. Common debugging steps:")
    print("- Check error message carefully")
    print("- Print variable values before error")
    print("- Simplify code to isolate problem")
    print("- Check MicroPython documentation")

# Usage
# try:
#     import nonexistent_module
# except Exception as e:
#     diagnose_error(e)

System Health Check

def health_check():
    """Comprehensive system health check"""
    print("=" * 50)
    print("SYSTEM HEALTH CHECK")
    print("=" * 50)

    issues = []

    # Memory check
    gc.collect()
    free_mem = gc.mem_free()
    if free_mem < 10000:
        issues.append("CRITICAL: Very low memory")
    elif free_mem < 50000:
        issues.append("WARNING: Low memory")
    else:
        print("✓ Memory: OK")

    # Filesystem check
    try:
        stat = os.statvfs('/')
        free_blocks = stat[3]
        block_size = stat[0]
        free_bytes = free_blocks * block_size

        if free_bytes < 100000:
            issues.append("WARNING: Low disk space")
        else:
            print("✓ Filesystem: OK")
    except:
        issues.append("ERROR: Cannot check filesystem")

    # Core modules check
    required = ['badger2040', 'machine', 'time', 'gc', 'sys', 'os']
    for module in required:
        try:
            __import__(module)
        except:
            issues.append(f"ERROR: Missing module '{module}'")

    if not issues:
        print("✓ Core modules: OK")

    # Display results
    if issues:
        print("\n" + "!" * 50)
        print("ISSUES FOUND:")
        for issue in issues:
            print(f"  {issue}")
        print("!" * 50)
    else:
        print("\n" + "=" * 50)
        print("✓ ALL SYSTEMS HEALTHY")
        print("=" * 50)

health_check()

Recovery Procedures

Safe Mode Boot

If badge won't boot normally:

  1. Hold BOOTSEL button while connecting USB
  2. Badge appears as USB drive
  3. Delete main.py if it's causing crashes
  4. Copy new firmware .uf2 file to drive
  5. Badge will reboot automatically

Factory Reset

import os

def factory_reset():
    """Remove all user files (DANGEROUS!)"""
    print("WARNING: This will delete all files!")
    print("Type 'CONFIRM' to proceed:")

    # In interactive mode, get user confirmation
    # confirm = input()
    # if confirm != 'CONFIRM':
    #     print("Reset cancelled")
    #     return

    print("Removing files...")
    for f in os.listdir('/'):
        if f not in ['boot.py']:  # Keep boot.py
            try:
                os.remove(f)
                print(f"  Removed {f}")
            except:
                pass

    print("Factory reset complete. Reboot badge.")

# Uncomment to use:
# factory_reset()

Firmware Reflash

# From your computer (badge in BOOTSEL mode)

# Download latest MicroPython firmware
# Visit: https://micropython.org/download/rp2-pico-w/

# Flash firmware
# Drag .uf2 file to RPI-RP2 drive
# Or use picotool:
picotool load firmware.uf2

# Verify
picotool info

Troubleshooting Checklist

When encountering issues, work through this checklist:

  • Check MicroPython version (sys.version)
  • Verify core modules load (import badger2040)
  • Run memory diagnostic (gc.mem_free())
  • Check filesystem space (os.statvfs('/'))
  • Test display (badge.update())
  • Test buttons (button test function)
  • Scan I2C bus (if using sensors)
  • Test WiFi connection (if using network)
  • Review error messages carefully
  • Check documentation for API changes
  • Try soft reset (Ctrl+D in REPL)
  • Try hard reset (power cycle)

This comprehensive diagnostic approach will help you quickly identify and resolve issues with your Badger 2350!