ajchellew / zwiftplay

An attempt at decoding the Zwift Play controllers
32 stars 4 forks source link

Support for Zwift Ride #5

Open Makinolo opened 3 months ago

Makinolo commented 3 months ago

If you ever want to support Zwift Ride, I've decoded the new protocol (way easier, not encrypted) and I have created a few .proto definitions that can read them. Here you have the .proto, the rest of the explanation you can find it in https://www.makinolo.com/blog/2024/07/26/zwift-ride-protocol/

syntax = "proto2";

//---------------- Zwift Play messages enum PlayButtonStatus { ON = 0; OFF = 1; } // The command code prepending this message is 0x07 message PlayKeyPadStatus { optional PlayButtonStatus RightPad = 1; optional PlayButtonStatus Button_Y_Up = 2; optional PlayButtonStatus Button_Z_Left = 3; optional PlayButtonStatus Button_A_Right = 4; optional PlayButtonStatus Button_B_Down = 5; optional PlayButtonStatus Button_On = 6; optional PlayButtonStatus Button_Shift = 7; optional sint32 Analog_LR = 8; optional sint32 Analog_UD = 9; }

message PlayCommandParameters { optional uint32 param1 = 1; optional uint32 param2 = 2; optional uint32 HapticPattern = 3; }

message PlayCommandContents { optional PlayCommandParameters CommandParameters = 1; }

// The command code prepending this message is 0x12 // This is sent to the control point to configure and make the controller vibrate message PlayCommand { optional PlayCommandContents CommandContents = 2; }

// The command code prepending this message is 0x19 // This is sent periodically when there are no button presses message Idle { optional uint32 Unknown2 = 2; }

//----------------- Zwift Ride messages enum RideButtonMask { LEFT_BTN = 0x00001; UP_BTN = 0x00002; RIGHT_BTN = 0x00004; DOWN_BTN = 0x00008; A_BTN = 0x00010; B_BTN = 0x00020; Y_BTN = 0x00040;

Z_BTN         = 0x00100;
SHFT_UP_L_BTN = 0x00200;
SHFT_DN_L_BTN = 0x00400;
POWERUP_L_BTN = 0x00800;
ONOFF_L_BTN   = 0x01000;
SHFT_UP_R_BTN = 0x02000;
SHFT_DN_R_BTN = 0x04000;

POWERUP_R_BTN = 0x10000;
ONOFF_R_BTN   = 0x20000;

}

enum RideAnalogLocation { LEFT = 0; RIGHT = 1; UP = 2; DOWN = 3; }

message RideAnalogKeyPress { optional RideAnalogLocation Location = 1; optional sint32 AnalogValue = 2; }

message RideAnalogKeyGroup { repeated RideAnalogKeyPress GroupStatus = 1; }

// The command code prepending this message is 0x23 message RideKeyPadStatus { optional uint32 ButtonMap = 1; optional RideAnalogKeyGroup AnalogButtons = 2; }

//------------------ Zwift Click messages // The command code prepending this message is 0x37 message ClickKeyPadStatus { optional PlayButtonStatus Button_Plus = 1; optional PlayButtonStatus Button_Minus = 2; }

//------------------ Device Information requested after connection // The command code prepending this message is 0x3c message DeviceInformationContent { repeated uint32 Unknown1 = 2;
optional string DeviceName = 3; optional string SerialNumber = 6; optional string HardwareVersion = 7; optional uint32 Unknown2 = 9; optional uint32 Unknown3 = 10; }

message SubContent { optional DeviceInformationContent Content = 1; }

message DeviceInformation { optional uint32 Unknown1 = 1; optional SubContent SubContent = 2; }

cagnulein commented 3 months ago

thanks for your work @Makinolo

ajchellew commented 3 months ago

@Makinolo indeed, thanks for this, I'll try to incorporate it into the app, a really good write up too.

I wonder if Zwift decided to make things all a bit easier to reverse engineer for third party uses, especially with the Zwift Ride is quite a big investment, and knowing it can be used by third parties might convince people to buy it over a completely closed bit of hardware.

cagnulein commented 3 months ago

@Makinolo chatting on some Zwift guys they told me that exist 2 different zwift ride devices on handlebar:

are you aware of?

Makinolo commented 3 months ago

No, I was not aware of that. Is there a physical difference between the two? Are those people tech savvy enough to give me more details? I would like to get in contact with more people owning the Ride, all my work is based in just one user. I frankly don't think there are 2 different versions, that would be a nightmare for integrators if they want to share the protocol with 3rd parties like they are doing with the Hub virtual gears protocol

cagnulein commented 3 months ago

No, I was not aware of that. Is there a physical difference between the two?

As far as I know,no, no difference at all.

Are those people tech savvy enough to give me more details? I would like to get in contact with more people owning the Ride,

I tried but I have nothing so far.

all my work is based in just one user.

Same here.

I frankly don't think there are 2 different versions, that would be a nightmare for integrators if they want to share the protocol with 3rd parties like they are doing with the Hub virtual gears protocol

Yeah :) let's keep up update eachother

mbrouwer commented 2 weeks ago

@Makinolo @cagnulein I have a Zwift Ride and id be happy to help out...

cagnulein commented 2 weeks ago

Thanks @mbrouwer I did everything on QZ https://github.com/cagnulein/qdomyos-zwift/

mbrouwer commented 2 weeks ago

Thanks @mbrouwer I did everything on QZ https://github.com/cagnulein/qdomyos-zwift/

Hi yeah I tried that this weekend, tried it on iOS and Android but the shifting didnt work, it is however 99% user error :) I do see there is a windows store app though so I might try that one...

cagnulein commented 2 weeks ago

@mbrouwer Contact me there with a debug log and I will tell you which is the issue on your setup https://github.com/cagnulein/qdomyos-zwift/wiki/How-do-i-get-the-debug-log-in-case-something-doesn't-work%3F