Skip to content

Python HTTP

The ESP32 web server exposes a REST endpoint that accepts JSON commands via HTTP GET. This is the simplest way to control the arm wirelessly from any language or tool that can make HTTP requests.

GET http://<arm-ip>/js?json=<url-encoded-json>

The arm’s IP depends on the WiFi mode:

  • AP mode: 192.168.4.1
  • STA mode: Assigned by your router (check with {"T":405} over serial)
Terminal window
pip install requests
import requests
import json
from urllib.parse import quote
ARM_IP = "192.168.4.1"
def send_command(cmd: dict) -> dict | None:
"""Send a JSON command via HTTP and return the response."""
url = f"http://{ARM_IP}/js?json={quote(json.dumps(cmd))}"
try:
resp = requests.get(url, timeout=2)
return resp.json()
except (requests.RequestException, json.JSONDecodeError):
return None
# Move to home
send_command({"T": 100})
# Get position feedback
pos = send_command({"T": 105})
if pos:
print(f"Position: ({pos['x']:.1f}, {pos['y']:.1f}, {pos['z']:.1f})")
# Move to coordinates
send_command({"T": 104, "x": 200, "y": 50, "z": 150, "t": 1.57, "spd": 0.25})
# Open gripper
send_command({"T": 106, "cmd": 1.57, "spd": 0, "acc": 0})
import time
def pick_and_place(pick_x, pick_y, place_x, place_y, height=150, grab_height=50):
"""Pick an object and place it at a new location."""
# Move above pick position
send_command({"T": 104, "x": pick_x, "y": pick_y, "z": height, "t": 3.14, "spd": 0.25})
time.sleep(1)
# Open gripper
send_command({"T": 106, "cmd": 1.57, "spd": 0, "acc": 0})
time.sleep(0.5)
# Lower to grab
send_command({"T": 104, "x": pick_x, "y": pick_y, "z": grab_height, "t": 3.14, "spd": 0.15})
time.sleep(1)
# Close gripper
send_command({"T": 106, "cmd": 3.14, "spd": 0, "acc": 0})
time.sleep(0.5)
# Lift
send_command({"T": 104, "x": pick_x, "y": pick_y, "z": height, "t": 3.14, "spd": 0.25})
time.sleep(1)
# Move to place position
send_command({"T": 104, "x": place_x, "y": place_y, "z": height, "t": 3.14, "spd": 0.25})
time.sleep(1)
# Lower to place
send_command({"T": 104, "x": place_x, "y": place_y, "z": grab_height, "t": 3.14, "spd": 0.15})
time.sleep(1)
# Release
send_command({"T": 106, "cmd": 1.57, "spd": 0, "acc": 0})
time.sleep(0.5)
# Return to safe height
send_command({"T": 104, "x": place_x, "y": place_y, "z": height, "t": 3.14, "spd": 0.25})
# Usage
pick_and_place(200, -50, 200, 50)

You can also control the arm directly from the command line:

Terminal window
# Home position
curl "http://192.168.4.1/js?json=%7B%22T%22%3A100%7D"
# Get feedback
curl "http://192.168.4.1/js?json=%7B%22T%22%3A105%7D"
# With jq for pretty output
curl -s "http://192.168.4.1/js?json=%7B%22T%22%3A105%7D" | jq .

For applications that send many commands, use a requests.Session to reuse the TCP connection:

import requests
import json
from urllib.parse import quote
session = requests.Session()
session.timeout = 2
ARM_IP = "192.168.4.1"
def send(cmd: dict):
url = f"http://{ARM_IP}/js?json={quote(json.dumps(cmd))}"
return session.get(url)
FeatureHTTPUART
ConnectionWireless (WiFi)Wired (USB)
Latency~10-50ms~5-10ms
ReliabilityNetwork-dependentVery reliable
RangeWiFi rangeCable length
Multi-clientYes (multiple browsers)Single connection
SetupWiFi config requiredPlug and play

HTTP control reference from the Waveshare Python HTTP guide and firmware source.