Remote driver/rider control interface for ReStim-compatible e-stim devices.
The rider runs ReDrive on their machine and connects it to ReStim. The driver opens a browser — on any device, including a phone — and takes control of patterns, intensity, electrode position, and more in real time.
- Pattern engine — Hold, Sine, Ramp, Pulse, Burst, Random, Edge
- Beta sweep — slow/fast oscillation between electrodes with skew (dwell bias toward A or B end)
- Spiral mode — quadrature beta/alpha sweep that tightens toward centre and auto-resets
- Intensity ramp — smooth ramp to target over configurable duration
- Touch interface — phone-friendly
/touchpage with anatomy overlay, vertical position/intensity axes, and A/B/C electrode assignment - Gesture looping — draw a gesture on the touch canvas, release, and it loops indefinitely
- Presets — one-click full state recall (includes Milking out of the box)
- Custom anatomy overlays — drop PNGs into
touch_assets/anatomy/to swap the anatomy graphic - Custom tool cursors — drop PNGs into
touch_assets/tools/(feather.png,hand.png,stroker.png)
pip install aiohttp
ReStim must be running and have its WebSocket server enabled (default ws://localhost:12346).
python redrive.py
| Who | What to open |
|---|---|
| Rider | Just run the script — keep the terminal visible for status |
| Driver (desktop) | http://<rider-ip>:8765 |
| Driver (phone) | http://<rider-ip>:8765/touch |
The rider always controls their own maximum power on their ReStim device. ReDrive only controls pattern shape and relative intensity within that limit.
On first run, redrive_config.json is created with defaults. Copy redrive_config.json.example as a starting point or edit the generated file directly.
| Key | Default | Description |
|---|---|---|
restim_url |
ws://localhost:12346 |
ReStim WebSocket address |
ctrl_port |
8765 |
Port for the driver browser UI |
axis_volume |
L0 |
T-code axis for intensity |
axis_beta |
L1 |
T-code axis for electrode position |
axis_alpha |
L2 |
T-code axis for alpha oscillation |
tcode_floor |
0 |
Minimum T-code value when intensity > 0 |
send_interval_ms |
50 |
Command send rate (ms) |
The /touch page has three anatomy positions (Tip, Balls, Anus) each assignable to electrode label A, B, or C:
- A = beta 0 (one physical wire end)
- B = beta 9999 (other physical wire end)
- C = beta 5000 (neutral centre)
Reassign to match however the rider has physically wired their electrode — no need to swap wires.
Presets are stored in two places that must stay in sync:
PRESETSdict near the top ofredrive.py(applied server-side)JS_PRESETSobject in theDRIVER_HTMLstring (updates the driver UI sliders)
Both are marked with a warning comment pointing at each other.
ReDrive can run on a public server so the driver uses a shareable URL instead of a LAN IP. Multiple riders connect to the same room simultaneously.
Driver browser ──POST /room/CODE/command──▶ server.py (DriveEngine per room)
│
T-code broadcast
│
Rider 1 rider_client.py ◀──WS /room/CODE/rider◀┘
Rider 2 rider_client.py ◀──WS /room/CODE/rider
The pattern engine lives on the server. rider_client.py is a thin bridge
that forwards T-code from the relay to the local ReStim WebSocket.
# On the server (as root):
bash server/setup.shThe script installs nginx, certbot, a Python venv, the systemd service, and
obtains a TLS certificate for redrive.estimstation.com.
On the rider's machine (the one connected to the ReStim device):
pip install aiohttp
python rider_client.py XXXXXXXXXX # 10-char code from driverThe rider can also open https://redrive.estimstation.com/room/CODE/touch
on their phone for the touch control page.
- 10 characters from an unambiguous alphabet (no 0/O/1/I/L)
- Each room expires after 24 hours of inactivity
- Driver copies the code via the banner shown at the top of the driver page
- ReStim by diglet48 — the e-stim engine this bridges to
- T-code protocol — standard used across the e-stim / toy ecosystem