Show us your zwift setup!

Hey Nick!
What I did… may very-well apply to different TRUE treadmills, and, potentially, different brands, as long as they have a similar motor controller. To reverse engineer the communication from the 20-pin(+) header located on the motor controller board (I’m 1300 miles away and can’t see it right now in my brain…), I first determined which of the wires were ground. Next, I ran the other wires (one-by-one) through an oscilloscope. Strangely, two wires were always strobing between 0 and 12 volts. AHA! Looked like RR-232. I measured the pulses-width of these strobing wires and and… it was about 104 microseconds. A-HA-- looks like 9600 baud!! Becoming very excited, I determined parity (none) and start-stop bits (none). The last step was to put an Arduino Uno D-3 in between the motor controller and the head-unit (display unit) and buffer / write-out all communication, before passing it along. This buffer-snoop worked very well. N.B. The Arduino will explode if you try to put 12 Volts into it’s puny digital input So I used a MAX-2232 chip to up/down regulate the 5V (Arduino) to 12V (treadmill).
Also N.B., the motor controller requires that keep-alive message be sent every 250 mSec. Any interruption to this causes the lower motor controller to shut-down requiring an wall-plug-unplug restart. Actually, it’s a pretty good fail safe.
The last step was to figure what gets passed up and down whenever a button is pressed. That part was pretty logical and pretty fun. The only difficult thing was determining the last byte’s CRC hash code. I’m happy to pass that part along.
I use a lot of serial communication. Some are SoftwareSerial.h 's
Ports used by the Arduino MEGA:
PORT
1 - To/From PC for programming
2 - To/From treadmill.
3 - To ESP-32 for Bluetooth Speed/Incline/HR/Odometer/Power/etc. GATT Service 0x1826
4 - To ESP-32 for Web-Server capability. It’s a local web-server serving up treadmill-controlling web-pages!
5 - To Nextion touch display Nextion Website

I also used I2C for motion (thump/cadence and lidar). This is buggy-- line noise over I2C can hang the mega irrevocably!

The donor treadmill is a TRUE CS-850-- a very well built beast of steel with a 5HP AC motor. Luckily, the motor controller does not allow rapid speed or grade shifts,(otherwise I would be dead).
Here’s the c++ Code for sendCommandCRC (calculates the CRC-checker byte) and setSpeed

void Treadmill::sendCommandCRC (char *szCommand,byte *command,byte s)
{
byte c2[s+1];
memcpy(c2, command, s);
byte crc = doCRC1 (command,s);
c2[s] = crc;
sendCommand(szCommand,c2,sizeof(c2)); //just prints the bytes to a serial port. szCommand is for debugging, it gets written to the computer serial port

}
void Treadmill::setSpeed (float fSpeed)
{
fSpeed = constrain (fSpeed,0,12); //12 MPH is my max
fTargetSpeed = fSpeed; //in MPH
fTargetSpeedK = fSpeed * 1.60934; // in KPH

static word lastMul = 0;

///used to be 0xb0c / 9.0
word mul = int(fSpeed * convMPH + yInt);
if (lastMul == mul) return; //no need to set speed to same speed if already done…
lastMul = mul;

if (fSpeed < 0.25) mul = 0; //no slow—>stop

byte command[] = {0x00,0xff,0xff,0x2f,0x02,((mul >> 8) & 0xff),mul & 0xff};
sendCommandCRC(“Speed1”,command,sizeof(command));

}
Good luck.