Proxy Objects

ProxyObject provides a way to interact with remote objects on your MicroPython or CircuitPython device as if they were local Python objects. This is useful for hardware peripherals, custom classes, or modules that cannot be serialized.

Overview

When executing code with task() or __call__(), return values must typically be serializable literals (numbers, strings, lists, dicts, etc.). ProxyObject creates a transparent wrapper for non-serializable objects, forwarding operations to the device automatically.

Creating Proxy Objects

Use Device.proxy() to create proxies:

from belay import Device

device = Device("/dev/ttyUSB0")

# Create and proxy a remote object
device("sensor = TemperatureSensor()")
sensor = device.proxy("sensor")
temp = sensor.temperature
sensor.calibrate()

# Import modules directly
machine = device.proxy("import machine")
pin = machine.Pin(25, machine.Pin.OUT)
pin.on()

Return Value Behavior

Values are automatically returned directly or as proxies based on type:

  • Immutable types (bool, int, float, str, bytes, none) → returned directly

  • Mutable types (list, dict, custom objects) → returned as ProxyObject

temp = sensor.temperature  # Returns float directly (e.g., 23.5)
config = sensor.config  # Returns ProxyObject wrapping dict
threshold = config["threshold"]  # Returns value directly

Working with Collections

Lists, dictionaries, and nested objects work transparently:

# Lists
device("data = [1, 2, 3, 4, 5]")
data = device.proxy("data")
print(data[0], data[-1])  # 1 5
data[0] = 100  # Modify remotely
print(len(data))  # 5
for item in data:  # Iterate
    print(item)

# Dictionaries
device("config = {'brightness': 10, 'mode': 'auto'}")
config = device.proxy("config")
brightness = config["brightness"]  # 10
config["brightness"] = 20
if "mode" in config:
    print("Mode configured")

Working with Methods and Modules

Call methods and use modules naturally:

# Methods
device("""
class LED:
    def __init__(self, pin):
        self.state = False
    def on(self):
        self.state = True
led = LED(25)
""")
led = device.proxy("led")
led.on()
print(led.state)  # True

# Modules
machine = device.proxy("import machine")
led_pin = machine.Pin(25, machine.Pin.OUT)  # remotely creates an led_pin object
led_pin.on()

Memory Management

Proxies automatically delete remote references when garbage collected. Use delete=False to prevent this:

# Auto-deletes micropython object when local object "temp" goes out-of-scope and garbage collected.
temp = device.proxy("temp_obj").value

# Never deletes micropython object
machine = device.proxy("import machine", delete=False)