Skip to content

Latest commit

 

History

History
813 lines (649 loc) · 23.9 KB

File metadata and controls

813 lines (649 loc) · 23.9 KB

circremote FAQ

General Questions

What is circremote?

circremote is a command-line tool for uploading and running Python code on CircuitPython devices. It supports both local serial connections and networked WebSocket connections (via CircuitPython Web Workflow), making it easy to remotely control and run programs on CircuitPython boards.

How do I install circremote?

The preferred and easiest way is to use PyPI:

pip install circremote
pip install git+https://github.com/romkey/circremote

For development, you can install in editable mode:

git clone https://github.com/romkey/circremote
cd circremote-python
pip install -e .

How do I use circremote under Windows?

I do not have access to a Windows machine and have not tried to use circremote on one. I cannot make any promises or offer any support for Windows users, sorry.

What devices does circremote support?

circremote works with any CircuitPython-compatible board, including:

  • Raspberry Pi Pico
  • Adafruit Feather boards
  • ESP32/ESP8266 boards
  • SAMD21/SAMD51 boards
  • And many others

How do I save a program using circremote?

You don't. circremote is intended to upload and run a program on a device without disturbing the software that's already stored on it. It does not currently support saving files to the device.

Command Usage

How do I run a basic command?

circremote /dev/ttyUSB0 BME280

How do I get help for a specific command?

# Show detailed help including tested status
circremote -h BME280

# Help shows:
# - Description of what the command does
# - Status: ✅ Tested, ⚠️ Not tested, or ❓ Unknown
# - Required and optional arguments with defaults
# - Usage examples

How do I specify variables for a command?

# Explicit variable assignment
circremote /dev/ttyUSB0 BME280 sda=board.IO1 scl=board.IO2

# Positional arguments (if defined in info.json)
circremote /dev/ttyUSB0 mycommand board.IO1 board.IO2

# Mix of both
circremote /dev/ttyUSB0 mycommand board.IO1 board.IO2 address=0x76

# Using device defaults (configured in config.json)
circremote my-device BME280  # Uses sda/scl/address from device config

How do I connect to a device over WiFi?

You must configure the device to support Web Workflow in order to connect over WiFi. Only devices with integrated WiFi (ESP32s, Raspberry Pi Pico W) support Web Workflow. Devices using an external ESP32 as a WiFi coprocessor, like the Adafruit Matrix Portal M4 - this is a limitation of CircuitPython.

# Using IP address (default port 80)
circremote 192.168.1.100 BME280

# Using IP address with custom port
circremote 192.168.1.100:8080 BME280

# With password
circremote -p mypassword 192.168.1.100 BME280

How do I use device defaults for variables?

You can configure default values for command variables on a per-device basis in your ~/.circremote/config.json file. This is especially useful for I2C pin assignments that are specific to your board layout.

Configuration Example:

{
  "devices": [
    {
      "name": "my-board",
      "device": "/dev/ttyUSB0",
      "defaults": {
        "sda": "board.IO1",
        "scl": "board.IO2",
        "address": "0x76"
      }
    }
  ]
}

Usage:

# Instead of specifying pins every time:
circremote /dev/ttyUSB0 BME280 sda=board.IO1 scl=board.IO2 address=0x76

# You can simply use:
circremote my-board BME280

Variable Resolution Priority:

  1. Command line values (highest priority) - sda=board.IO5
  2. Device defaults (from config.json) - sda: "board.IO1"
  3. Global variable defaults (from config.json) - sda: "board.SDA"
  4. Command defaults (from info.json) - "default": "board.SDA"

How do I use global variable defaults?

You can configure global default values for command variables that apply to all devices and commands in your ~/.circremote/config.json file. This is useful for setting common defaults like I2C pins that are consistent across your setup.

Configuration Example:

{
  "variable_defaults": {
    "sda": "board.SDA",
    "scl": "board.SCL",
    "address": "0x76"
  },
  "devices": [
    {
      "name": "my-board",
      "device": "/dev/ttyUSB0",
      "defaults": {
        "sda": "board.IO1",
        "scl": "board.IO2"
      }
    }
  ]
}

Usage:

# Global defaults apply to all commands unless overridden
circremote /dev/ttyUSB0 BME280  # Uses global sda/scl, command default address
circremote my-board BME280      # Uses device sda/scl, global address
circremote /dev/ttyUSB0 BME280 sda=board.IO5  # Overrides all defaults

Benefits:

  • Consistent defaults: Set common values once for all commands
  • Device overrides: Device-specific defaults still take precedence
  • Command overrides: Command line values always take highest priority
  • Reduced typing: No need to specify common variables repeatedly

How do I use remote commands from URLs?

circremote supports running commands directly from URLs, including GitHub repositories and other web servers.

Remote Command Directory (any URL not ending in .py):

# Fetch code.py, info.json, and requirements.txt from a directory
circremote /dev/ttyUSB0 https://github.com/user/repo/sensor/
circremote /dev/ttyUSB0 https://example.com/sensors/temperature/
circremote /dev/ttyUSB0 https://github.com/user/repo/tree/main/commands/sensor
circremote /dev/ttyUSB0 https://github.com/romkey/circremote/tree/main/circremote/commands/BME680

Remote Python File (ends with .py):

# Fetch a Python file and associated metadata
circremote /dev/ttyUSB0 https://example.com/sensor.py
circremote /dev/ttyUSB0 https://raw.githubusercontent.com/user/repo/main/sensor.py

Single File (any other URL):

# Fetch a single file (existing behavior)
circremote /dev/ttyUSB0 https://example.com/script.py

Features:

  • Automatic metadata: For directory URLs (any URL not ending in .py), circremote fetches code.py, info.json, and requirements.txt
  • Associated files: For Python files, circremote tries to fetch info.json and requirements.txt in the same directory
  • Dependency installation: Remote requirements.txt files trigger automatic circup installation
  • GitHub support: GitHub URLs are automatically converted to raw content URLs
  • Variable support: Remote commands support the same variable interpolation as local commands

Example with dependencies:

# This will fetch the command and install any required libraries
circremote /dev/ttyUSB0 https://github.com/user/repo/sensor/
# If requirements.txt exists, circup will be run automatically

How do I enable verbose output?

circremote -v /dev/ttyUSB0 BME280

How do I use quiet mode?

# Quiet mode - suppresses all circremote output except device output
circremote -q /dev/ttyUSB0 BME280

# Quiet mode with auto-confirm (skips all prompts)
circremote -q -y /dev/ttyUSB0 BME280

# Quiet mode with skip-circup (if dependencies need to be installed)
circremote -q -c /dev/ttyUSB0 BME280

Quiet mode behavior:

  • Suppresses: All circremote messages, warnings, progress info, module descriptions
  • Shows: Only output from the CircuitPython device
  • Exits with error: If any confirmation is needed (untested commands, offline warnings, dependencies)
  • Use with -y: Combine with -y to auto-confirm all prompts in quiet mode
  • Use with -c: Combine with -c to skip dependency installation in quiet mode

Note: Cannot be used with -v (verbose) option - they are mutually exclusive.

How do I skip dependency installation?

circremote -c /dev/ttyUSB0 BME280

How do I specify a custom circup path?

# Command line option
circremote -u /usr/local/bin/circup /dev/ttyUSB0 BME280
circremote -u ~/venv/bin/circup /dev/ttyUSB0 BME280

# Config file option

Add to your ~/.circremote/config.json:

{
  "circup": "/usr/local/bin/circup"
}

Precedence order:

  1. Command line option (-u PATH) - highest priority
  2. Config file setting ("circup": "PATH")

How do I use a custom config file?

# Use a different config file
circremote -C /path/to/custom.json /dev/ttyUSB0 BME280
circremote -C ~/projects/my_config.json 192.168.1.100 BME280

# Useful for:
# - Testing different configurations
# - Using different device sets for different projects
# - Sharing configurations with team members
  1. System PATH resolution (circup) - default

How do I set a timeout for output?

# Wait 30 seconds for output
circremote -t 30 /dev/ttyUSB0 BME280

# Wait indefinitely
circremote -t 0 /dev/ttyUSB0 BME280

Why Can't I Access My Raspberry Pi Pico W over the network?

Wifi-enabled Raspberry Pi Pico W boards do not support the Web Workflow. Only ESP32 CPUs support it.

Device Configuration

How do I set up shortcut names for devices?

Create a config file at ~/.circremote/config.json:

{
  "devices": [
    {
      "name": "pico1",
      "device": "/dev/ttyACM0",
      "friendly_name": "Raspberry Pi Pico"
    },
    {
      "name": "feather1",
      "device": "192.168.1.100:8080",
      "password": "mypassword",
      "friendly_name": "Adafruit Feather ESP32"
    }
  ]
}

Then use the shortcut name:

circremote pico1 BME280
circremote feather1 BME280

How do I set up command aliases?

Add command aliases to your config file:

{
  "command_aliases": [
    {
      "name": "temp",
      "command": "BME280"
    },
    {
      "name": "light",
      "command": "TSL2591"
    }
  ]
}

Then use the alias:

circremote /dev/ttyUSB0 temp

Custom Commands

How do I create my own commands?

You can create commands in several ways:

1. Python file directly

Create a Python file and run it directly:

circremote /dev/ttyUSB0 ./my_sensor.py

2. Command directory structure

Create a directory with the required files:

my_command/
├── code.py          # Required: Your Python code
├── info.json        # Optional: Command metadata and variables
└── requirements.txt # Optional: Dependencies

Then run it:

circremote /dev/ttyUSB0 ./my_command

3. Using search paths

Add custom command directories to your config:

{
  "search_paths": [
    "/path/to/my/commands",
    "~/custom_sensors",
    "/opt/circremote/commands"
  ]
}

Commands in these directories will be available by name:

circremote /dev/ttyUSB0 my_custom_sensor

What should I include in info.json?

{
  "name": "My Custom Sensor",
  "description": "A custom temperature and humidity sensor",
  "tested": true,
  "variables": [
    {
      "name": "sda",
      "description": "I2C SDA pin",
      "default": "board.SDA"
    },
    {
      "name": "scl", 
      "description": "I2C SCL pin",
      "default": "board.SCL"
    }
  ],
  "default_commandline": "sda scl"
}

How do I use template variables in my code?

In your code.py, use {{variable_name}} syntax:

import board
import busio
from adafruit_bme280 import basic as adafruit_bme280

# These will be replaced with actual values
i2c = busio.I2C({{scl}}, {{sda}})
bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c)

print(f"Temperature: {bme280.temperature}°C")

Loading Commands from the Web

circremote is able to download code from a web server and send it to a CircuitPython device. It currently only downloads the code; it cannot handle library dependencies or get information about the code from an info.json file.

Please be careful downloading random code from a web site. Even on a CircuitPython device it could contain malicious code which could share your WiFi credentials or other information stored on the device with bad actors.

How do I run a command from GitHub?

circremote automatically rewrites Github URLs to properly access the file managed at that URL. These two examples are identical:

# Direct GitHub URL
circremote /dev/ttyUSB0 https://github.com/adafruit/Adafruit_CircuitPython_BME680/blob/main/examples/bme680_simpletest.py`

# GitHub raw URL
circremote /dev/ttyUSB0 https://raw.githubusercontent.com/adafruit/Adafruit_CircuitPython_BME680/main/examples/bme680_simpletest.py

Be aware that circremote will not automatically install the BME680 library if you run this code this way. It will if you run the local BME680 command.

How do I run a command from other websites?

# Any HTTP/HTTPS URL
circremote /dev/ttyUSB0 https://romkey.com/circup/hello.py

Can I use URLs with directories?

Yes, circremote will automatically try to load code.py, info.json and requirements.txt files from URLs that aren't Python files.

Troubleshooting

"Command not found" error

This usually means:

  1. The command name is misspelled
  2. The command doesn't exist in the built-in library
  3. The command isn't in your search paths

Check available commands:

circremote -l

"Connection refused" error

For serial connections:

  • Check if the device is connected
  • Verify the port name (e.g., /dev/ttyUSB0, /dev/ttyACM0)
  • Make sure no other program is using the port

For WebSocket connections:

  • Verify the IP address and port
  • Check if CircuitPython Web Workflow is enabled on the device
  • Ensure the device is on the same network

"Bad password" error

For WebSocket connections:

  • Check your password in the config or -p option
  • Verify the password matches CIRCUITPY_WEB_API_PASSWORD in settings.toml on the device
  • Restart the device after changing the password

"Permission denied" error

For serial connections:

  • Add your user to the dialout group (Linux):
    sudo usermod -a -G dialout $USER
  • On macOS, you might need to install drivers for your device

"Module not found" error

This means a required library isn't installed on the device:

  1. Check if the command has a requirements.txt file
  2. Make sure circup is installed: pip install circup
  3. Try running without -C flag to install dependencies automatically

"Template variables found but no variables available"

Your code uses template variables (like {{sda}}) but no values were provided:

# Provide values on command line
circremote /dev/ttyUSB0 BME280 sda=board.IO1 scl=board.IO2

# Or define defaults in info.json

"Invalid variables provided" error

You provided a variable that isn't defined in the command's info.json:

  1. Check the command's documentation for valid variables
  2. Look at the info.json file to see what variables are expected
  3. Use -v flag to see debug information

"Circup not found" error

Install circup to manage CircuitPython dependencies:

pip install circup

If circup is installed but not found, specify the path:

# Command line
circremote -c /usr/local/bin/circup /dev/ttyUSB0 BME280

# Config file

Add to ~/.circremote/config.json:

{
  "circup": "/usr/local/bin/circup"
}

Common circup locations:

  • /usr/local/bin/circup (pip install)
  • /opt/homebrew/bin/circup (Homebrew on macOS)
  • ~/venv/bin/circup (virtual environment)
  • circup (system PATH)

Device not responding

  1. Check the connection (serial port or IP address)
  2. Try pressing the reset button on the device
  3. Verify the device is running CircuitPython
  4. Check if the device is in bootloader mode (some boards have a boot button)

WebSocket connection timeout

  1. Check if the device is running CircuitPython Web Workflow
  2. Verify the IP address and port
  3. Check your network connection
  4. Try restarting the device

Advanced Usage

How do I run commands with different timeouts?

# Wait 5 seconds for output
circremote -t 5 /dev/ttyUSB0 BME280

# Wait indefinitely (until you press Ctrl+C)
circremote -t 0 /dev/ttyUSB0 BME280

How do I use "double exit" mode?

Use "double exit mode" to send an extra ^D to the device in order to re-start the program in code.py:

circremote -d /dev/ttyUSB0 BME280

How do I skip confirmation prompts?

circremote -y /dev/ttyUSB0 untested_command

How do I see what's happening internally?

If something goes wrong and you want detailed debugging info, use the -v or --verbose flag.

circremote -v /dev/ttyUSB0 BME280

Configuration File Security

Why do I get a warning about file permissions?

If your config file has world-readable permissions, you'll see a warning. Fix it:

chmod 600 ~/.circremote/config.json

What should I include in my config file?

{
  "devices": [
    {
      "name": "my-device",
      "device": "/dev/ttyUSB0",
      "friendly_name": "My CircuitPython Device"
    }
  ],
  "command_aliases": [
    {
      "name": "temp",
      "command": "BME280"
    }
  ],
  "search_paths": [
    "~/my_commands",
    "/opt/custom_sensors"
  ],
  "circup": "/usr/local/bin/circup"
}

What serial ports can I use?

macOS/Linux:

  • /dev/ttyUSB0 - USB-to-serial adapter
  • /dev/ttyACM0 - Arduino-style device
  • /dev/ttyS0 - Built-in serial port

Windows:

  • COM1, COM2, COM3, etc. - Standard Windows COM ports
  • Check Device Manager to find the correct COM port number

Finding your port:

# macOS/Linux
ls /dev/tty*

# Windows
# Check Device Manager > Ports (COM & LPT)

How do I fix serial port permission issues?

macOS/Linux:

# Check if user is in dialout group
groups $USER

# Add user to dialout group
sudo usermod -a -G dialout $USER

# Log out and back in, or run:
newgrp dialout

Windows:

  • Run as Administrator if permission denied
  • Check Device Manager for port conflicts
  • Ensure device drivers are installed

What if circremote is not recognized on Windows?

If you get an error like 'circremote' is not recognized as an internal or external command, Python or the pip installation directory is not in your Windows PATH.

Solution: Add Python to Windows PATH

  1. Find your Python installation:

    python --version

    If this works, note the Python version. If not, you need to install Python first.

  2. Find your pip installation directory:

    python -m site --user-base

    This will show something like C:\Users\YourUsername\AppData\Local\Programs\Python\Python3x\Lib\site-packages

  3. Add Python Scripts to PATH:

    • Press Win + R, type sysdm.cpl, press Enter
    • Click "Environment Variables"
    • Under "User variables", find "Path" and click "Edit"
    • Click "New" and add: C:\Users\YourUsername\AppData\Local\Programs\Python\Python3x\Scripts
    • Replace YourUsername with your actual username
    • Replace Python3x with your Python version (e.g., Python39, Python310)
    • Click "OK" on all dialogs
  4. Alternative: Use Python module directly:

    python -m circremote COM3 BME280
  5. Restart your command prompt and try again:

    circremote --version

Note: If you installed Python with the Microsoft Store, the path might be different. Use where python to find the correct location.

How does the timeout feature work?

The -t or --timeout option sets a maximum time (in seconds) for circremote to wait for output from the device.

Behavior:

  • Serial connections: Timeout applies to waiting for device output
  • WebSocket connections: Timeout applies to connection establishment
  • Default: 10 seconds if not specified
  • Disable: Use -t 0 to disable timeout

Cross-platform compatibility:

  • Windows: Uses threading.Timer for timeout handling
  • macOS/Linux: Uses signal.SIGALRM with threading.Timer fallback
  • All platforms: Timeout properly exits circremote when reached

Example:

# Wait up to 30 seconds for output
circremote -t 30 /dev/ttyUSB0 BME280

# Wait up to 5 seconds for output
circremote -t 5 COM3 scan-i2c

# No timeout (wait indefinitely)
circremote -t 0 /dev/ttyUSB0 long_running_command

How do I set up CircuitPython Web Workflow?

CircuitPython Web Workflow allows you to connect to devices over the network instead of USB.

Prerequisites:

  • ESP32-based CircuitPython device (ESP32, ESP32-S2, ESP32-S3, ESP32-C3, ESP32-C6, ESP32-H2)
  • Device connected to WiFi network
  • Device has network connectivity
  • CIRCUITPY drive unmounted (the command will check this automatically)

Setup Steps:

  1. Unmount CIRCUITPY drive (if mounted):

    # macOS
    sudo umount /Volumes/CIRCUITPY
    
    # Linux
    sudo umount /media/username/CIRCUITPY
    
    # Windows
    # Right-click on CIRCUITPY drive → Eject
  2. Configure Web Workflow:

    # Configure with your WiFi network, port, and Web Workflow password
    circremote /dev/ttyUSB0 enable-webworkflow "MyWiFiNetwork" "mypassword" 8080 "webpass"
  3. Restart the device to apply the configuration

  4. Test the connection:

    # Connect using Web Workflow (use device's actual IP address)
    circremote 192.168.1.100:8080 -p webpass system-info

Configuration Details:

  • WiFi SSID: Your WiFi network name
  • WiFi Password: Your WiFi network password
  • Port: Web server port (default: 8080, range: 1-65535)
  • Web Workflow Password: Password for Web Workflow authentication

Troubleshooting:

  • Ensure device is connected to WiFi
  • Check that the IP address is correct and reachable
  • Verify the port isn't blocked by firewall
  • Make sure the password matches what you configured

How do I use the enable-webworkflow command?

The enable-webworkflow command configures both WiFi and Web Workflow settings on ESP32 devices in one step.

Command Format:

circremote <device> enable-webworkflow <wifi_ssid> <wifi_password> <port> <web_workflow_password>

Example:

circremote /dev/ttyUSB0 enable-webworkflow "MyWiFi" "wifipass123" 8080 "webpass456"

What it does:

  1. Checks filesystem mount status - Ensures CIRCUITPY is unmounted
  2. Validates ESP32 compatibility - Confirms the device supports Web Workflow
  3. Writes configuration to settings.toml:
    • CIRCUITPY_WIFI_SSID - WiFi network name
    • CIRCUITPY_WIFI_PASSWORD - WiFi password
    • CIRCUITPY_WEB_API_PASSWORD - Web Workflow authentication password
    • CIRCUITPY_WEB_API_PORT - Web server port
  4. Provides next steps - Instructions for restarting and connecting

Safety Features:

  • Warns about offline risk - Command may make device unreachable
  • Prevents overwriting - Won't overwrite existing configuration
  • Mount detection - Automatically detects if CIRCUITPY is mounted
  • Port validation - Ensures port number is valid (1-65535)

After running the command:

  1. Restart your CircuitPython device
  2. Device connects to WiFi automatically
  3. Find device IP address (check serial output)
  4. Use circremote with Web Workflow: circremote <ip>:<port> -p <web_password> <command>

Resources:

How do I use quiet mode?

# Quiet mode - suppresses all circremote output except device output
circremote -q /dev/ttyUSB0 BME280

# Quiet mode with auto-confirm (skips all prompts)
circremote -q -y /dev/ttyUSB0 BME280

# Quiet mode with skip-circup (if dependencies need to be installed)
circremote -q -c /dev/ttyUSB0 BME280

Quiet mode behavior:

  • Suppresses: All circremote messages, warnings, progress info, module descriptions
  • Shows: Only output from the CircuitPython device
  • Exits with error: If any confirmation is needed (untested commands, offline warnings, dependencies)
  • Use with -y: Combine with -y to auto-confirm all prompts in quiet mode
  • Use with -c: Combine with -c to skip dependency installation in quiet mode

Note: Cannot be used with -v (verbose) option - they are mutually exclusive.