Repair or hack pro-form Tour de France exercise bike.

Thread Starter

ericspetersen

Joined Jan 2, 2022
2
Hello,
I have a Pro-Form Le Tour de France exercise bike. The console buttons have stopped working, and I have been unable to diagnose the issue. The console button matrix is decoded through a pair of hc165 parallel to serial shift registers. It appears that the clock input to these devices is only about 75mV. The clock signal comes from a Renasas R5F212DASNFP MCU. If I can't fix the console, my backup plan is to replace the console with a raspberry pi. Does anybody have any info on the interface to the control board? It needs to control the incline and the magnetic resistance of the flywheel.
 

kilomotor

Joined Jan 17, 2022
13
I have a proform too. So far all controls work but I'd be interest in adding an Rpi to handle the controls and broadcast power via Ant+ to interact with 3rd party training software. I will start poking around inside to see what I can find and report back.
 

Thread Starter

ericspetersen

Joined Jan 2, 2022
2
I have a proform too. So far all controls work but I'd be interest in adding an Rpi to handle the controls and broadcast power via Ant+ to interact with 3rd party training software. I will start poking around inside to see what I can find and report back.
I have a proform too. So far all controls work but I'd be interest in adding an Rpi to handle the controls and broadcast power via Ant+ to interact with 3rd party training software. I will start poking around inside to see what I can find and report back.
Thanks kilomotor,
I would be very interested in the signals generated to the lower control board when you change the incline or shift the gears while in manual mode.
 
Hi - any assistance appreciated. I have a Proform Tour de France PFEVEX71516. After being switched off for 2 years the screen rolls between white and striped. It briefly loaded the software but now just loops. When first switched on it makes the start up noise.
 

kilomotor

Joined Jan 17, 2022
13
I've finally had time to take a detailed look at my Proform bike and can provide details about the protocol to send signals from the handlebar console to the lower control board.
My bike is ver.1, sold at Canadiantire.ca. The Model#PFEX0118C.0. It has a basic LED console between the handlebars with a 7 segment style display to show time, speed, watts, grade, gear, etc. It has bluetooth capability for HRM and also for the IFit app to connect and control the bike.
Inside the console, there are 4 wires leading to the lower control board. Red (+9V), black (GND), green and blue. The green and blue carry the signals from the console to the lower control board in a modified RS485 protocol - modified being that it is operating at 3.3, not 5v. The blue wire is pulled high to 3.3v and the green wire is held low at 0v. When a signal is sent from console to control board, the blue wire signal is low and the green is high - both signals are added together as a sort of common mode noise rejection strategy (see RS485 signals for more info). The signals are sent as a series of bytes at 38400 baud, LSB first, 8 bits, no parity. In normal operation, the console sends a command to the control board and it responds back with the echoed command at 2Hz. I think the control board probably sends info about cadence to the console (and other info) but I haven't spent time decoding the return signals.

To change the incline, the following command would be sent:
0xBA, 0xB4, 0xB1, 0xB0, 0xB6, 0xB0, 0xB0, 0xB0, 0xB0, 0xB1, 0xB0, 0xB1, 0xC3, 0xB9, 0xC3, 0x8D, 0x8A
That would change the incline down one notch to -0.5. The important bytes are the second (0xB4) which indicates that the command is to change the incline and 12 to 15 (0xB1, 0xC3, 0xB9, 0xC3) which tell the console which level to shift to in absolute terms. There are 61 different codes(!) for bytes 12 to 15 corresponding to each half step in the incline of the bike.

To change the gear (resistance), this command would be sent:
0xBA, 0xB6, 0xB1, 0xB0, 0xB6, 0xB0, 0xB0, 0xB0, 0xB0, 0xB1, 0xB0, 0xB0, 0xB0, 0xC2, 0xB8, 0x8D, 0x8A
This would change the "gear" to #2. Note the important second byte (0xB6) indicating that a gear change is sent and bytes 12 to 15 indicate the level to move the resistance servo. I mapped out 22 levels for the gears, but the bytes are not sequential, unlike the incline levels so I believe there are many more levels of resistance possible (more on this later).

With this knowledge, I have created a small Arduino circuit and sketch which is capable of controlling the incline and gears of the bike. I will attach the file; it is worth a read at least to see the bytes for incline and gear changes. I will add a bit more detail in a blog post: https://forum.allaboutcircuits.com/...se-bike-reverse-engineering-more-info.656059/
 

Attachments

Hi there from Moldova. Very interested in this forum topic. Not long ago I bought a TDF bike 5.0, which had (according to the description) both motors damaged, both in terms of resistance and inclination. The motors were repaired by me, they work perfectly, motor feedback (variable potentiometer on resistance motor, and hall effect sensor on inline motor also work) but another problem appeared.
And before I throw away all smart electronics and make this bike only electro-mechanical controlled, I came across this great topic, and I want to ask you, maybe you have any ideas...
The problem is in the incline sensor, the console constantly jumps to -10 degrees, even after you change incline angle it jumps back to -10 degrees, and in general the unresponsiveness of the system. That is, each action occurs 2...3 seconds after the button is pushed and hold for a second at lest. Calibration and factory reset did not change anything. (Interesting that Android 2.0 system, that is used in console tablet, when you force stop iFit app, work blazingly fast from the same buttons)
Do you know what is responsible for reading the current level of inclination? (I think that is purely mathematical calculation, during the calibration, number the rotation (with hallefect senzor) from end to end of incline travel, and then go to the middle.... But this do not explane me, why it jumps to -10 degrees all the time). I looked on the control board for a gyroscope or another IC that would perform this function, and I didn't find anything. Incline motor has only a hall effect sensor that is activated by the magnet located in motor shaft, so it count only number of rotation.
Do you have any idea at what inclination is it in real time and why it jumps to -10 degrees?
 

Corey N.

Joined Dec 15, 2022
4
I've finally had time to take a detailed look at my Proform bike and can provide details about the protocol to send signals from the handlebar console to the lower control board.
My bike is ver.1, sold at Canadiantire.ca. The Model#PFEX0118C.0. It has a basic LED console between the handlebars with a 7 segment style display to show time, speed, watts, grade, gear, etc. It has bluetooth capability for HRM and also for the IFit app to connect and control the bike.
Inside the console, there are 4 wires leading to the lower control board. Red (+9V), black (GND), green and blue. The green and blue carry the signals from the console to the lower control board in a modified RS485 protocol - modified being that it is operating at 3.3, not 5v. The blue wire is pulled high to 3.3v and the green wire is held low at 0v. When a signal is sent from console to control board, the blue wire signal is low and the green is high - both signals are added together as a sort of common mode noise rejection strategy (see RS485 signals for more info). The signals are sent as a series of bytes at 38400 baud, LSB first, 8 bits, no parity. In normal operation, the console sends a command to the control board and it responds back with the echoed command at 2Hz. I think the control board probably sends info about cadence to the console (and other info) but I haven't spent time decoding the return signals.

To change the incline, the following command would be sent:
0xBA, 0xB4, 0xB1, 0xB0, 0xB6, 0xB0, 0xB0, 0xB0, 0xB0, 0xB1, 0xB0, 0xB1, 0xC3, 0xB9, 0xC3, 0x8D, 0x8A
That would change the incline down one notch to -0.5. The important bytes are the second (0xB4) which indicates that the command is to change the incline and 12 to 15 (0xB1, 0xC3, 0xB9, 0xC3) which tell the console which level to shift to in absolute terms. There are 61 different codes(!) for bytes 12 to 15 corresponding to each half step in the incline of the bike.

To change the gear (resistance), this command would be sent:
0xBA, 0xB6, 0xB1, 0xB0, 0xB6, 0xB0, 0xB0, 0xB0, 0xB0, 0xB1, 0xB0, 0xB0, 0xB0, 0xC2, 0xB8, 0x8D, 0x8A
This would change the "gear" to #2. Note the important second byte (0xB6) indicating that a gear change is sent and bytes 12 to 15 indicate the level to move the resistance servo. I mapped out 22 levels for the gears, but the bytes are not sequential, unlike the incline levels so I believe there are many more levels of resistance possible (more on this later).

With this knowledge, I have created a small Arduino circuit and sketch which is capable of controlling the incline and gears of the bike. I will attach the file; it is worth a read at least to see the bytes for incline and gear changes. I will add a bit more detail in a blog post: https://forum.allaboutcircuits.com/...se-bike-reverse-engineering-more-info.656059/
Kilomotor,

Thanks for all this I have found another Gentleman that figured away of Connecting the Old Pro-form TDF Bike to Zwift, I truly believe a combination your both of your work could add new life to a exercise bike that was plagued with firmware issues and was limited to interfacing with I-Fit such is the case with my bike that is like new but the firmware crashed. I do not wat to violate any form rules by posting other sites links hers but if you would like the other gentleman's post link please let me know. In the mean time it looks like I will be testing both of your modifications as the firmware on my 2012 model is no longer supported but the bike is like new. Thanks once more.
 

MrChips

Joined Oct 2, 2009
30,795
Kilomotor,

Thanks for all this I have found another Gentleman that figured away of Connecting the Old Pro-form TDF Bike to Zwift, I truly believe a combination your both of your work could add new life to a exercise bike that was plagued with firmware issues and was limited to interfacing with I-Fit such is the case with my bike that is like new but the firmware crashed. I do not wat to violate any form rules by posting other sites links hers but if you would like the other gentleman's post link please let me know. In the mean time it looks like I will be testing both of your modifications as the firmware on my 2012 model is no longer supported but the bike is like new. Thanks once more.
I don't see that you are violating any forum rules that help members to repair a unit.
That is what we're here for.
 

Corey N.

Joined Dec 15, 2022
4

MrChips

Joined Oct 2, 2009
30,795
In that case, if I am with in form rules the other gentleman's name is Old_Tekkie and the link to his post is https://www.instructables.com/Connecting-Old-Pro-form-TDF-Bike-to-Zwift/
I hope this information benefits everyone and I am just the facilitator for sharing the information, credit for all the work goes to the authors and I thank them.
Thanks for the link and sharing this information. It should prove to be useful for anyone wanting to hack into their exercise bike.
 

dgrekov

Joined Jan 8, 2023
15
I've finally had time to take a detailed look at my Proform bike and can provide details about the protocol to send signals from the handlebar console to the lower control board.
My bike is ver.1, sold at Canadiantire.ca. The Model#PFEX0118C.0. It has a basic LED console between the handlebars with a 7 segment style display to show time, speed, watts, grade, gear, etc. It has bluetooth capability for HRM and also for the IFit app to connect and control the bike.
Inside the console, there are 4 wires leading to the lower control board. Red (+9V), black (GND), green and blue. The green and blue carry the signals from the console to the lower control board in a modified RS485 protocol - modified being that it is operating at 3.3, not 5v. The blue wire is pulled high to 3.3v and the green wire is held low at 0v. When a signal is sent from console to control board, the blue wire signal is low and the green is high - both signals are added together as a sort of common mode noise rejection strategy (see RS485 signals for more info). The signals are sent as a series of bytes at 38400 baud, LSB first, 8 bits, no parity. In normal operation, the console sends a command to the control board and it responds back with the echoed command at 2Hz. I think the control board probably sends info about cadence to the console (and other info) but I haven't spent time decoding the return signals.

To change the incline, the following command would be sent:
0xBA, 0xB4, 0xB1, 0xB0, 0xB6, 0xB0, 0xB0, 0xB0, 0xB0, 0xB1, 0xB0, 0xB1, 0xC3, 0xB9, 0xC3, 0x8D, 0x8A
That would change the incline down one notch to -0.5. The important bytes are the second (0xB4) which indicates that the command is to change the incline and 12 to 15 (0xB1, 0xC3, 0xB9, 0xC3) which tell the console which level to shift to in absolute terms. There are 61 different codes(!) for bytes 12 to 15 corresponding to each half step in the incline of the bike.

To change the gear (resistance), this command would be sent:
0xBA, 0xB6, 0xB1, 0xB0, 0xB6, 0xB0, 0xB0, 0xB0, 0xB0, 0xB1, 0xB0, 0xB0, 0xB0, 0xC2, 0xB8, 0x8D, 0x8A
This would change the "gear" to #2. Note the important second byte (0xB6) indicating that a gear change is sent and bytes 12 to 15 indicate the level to move the resistance servo. I mapped out 22 levels for the gears, but the bytes are not sequential, unlike the incline levels so I believe there are many more levels of resistance possible (more on this later).

With this knowledge, I have created a small Arduino circuit and sketch which is capable of controlling the incline and gears of the bike. I will attach the file; it is worth a read at least to see the bytes for incline and gear changes. I will add a bit more detail in a blog post: https://forum.allaboutcircuits.com/...se-bike-reverse-engineering-more-info.656059/
This is amazing work, have you done any further analysis? I have a similar bike and the control panel has broken. Trying to set up the same as you. Have an Arduino with a MAX3489 set up. That's the 3.3V version. Not having much luck getting a response yet, but that may be due to how I have it hooked up. Would love to collaborate and see if we can get it working.
 

kilomotor

Joined Jan 17, 2022
13
This is amazing work, have you done any further analysis? I have a similar bike and the control panel has broken. Trying to set up the same as you. Have an Arduino with a MAX3489 set up. That's the 3.3V version. Not having much luck getting a response yet, but that may be due to how I have it hooked up. Would love to collaborate and see if we can get it working.
Wow, this thread was dead for so long, but has come alive with many new posts. Great to see that others are willing to try hacking/modding the Proform bike. It is a great flywheel and resistance but I'd love to unleash it's capabilities without a subscription to iFit. I will try to address all the previous questions and provide a roadmap as to what I was planning to do to with my Proform.

1. Mr. Chips (Dec 15) posted pictures of a bike that is exactly like mine. I know there are several different models and I would guess that ones with wifi or a builtin tablet operate on different hardware and in a different way.

2. @SunnyWideSky, I don't know what sets the incline of the bike. I suspect a potentiometer in the incline motor feeds a resistance to the lower control board, and that is sent back to the head unit. I will investigate in the next few days and report back, it should be easy to track down. I don't know why your unit is unresponsive -- I would say that mine is a bit laggy, maybe 0.5 seconds from button press to movement. I wonder if interference on the RS485 lines?

3. @Corey N., thanks for the link to the Zwift hack. I had encountered this instructable before, but am unsure if this is the path for me. To interface with Zwift, a reasonable power calculation is needed to feed to Zwift. All speeds and hence distance in game come from the power numbers from the trainer or bike. The power numbers seem off on my bike -- too high at low speeds and far too low at max effort. I can't get above 200watts in full sprint and I must be a better cyclist than that, right? ;^)

4. @dgrekov, if I can help get your Arduino interfaced with the bike, let me know. It was fairly straight forward to control my bike with the Arduino setup but if you have a different bike it might not be the same at all! I had to use a 5v RS485 module and level shifter because that was all I had available.

I have been thinking of many ideas that I would like to incorporate into the Proform; time is the only issue! My first priorities when I have some more time available will be power calculation and remote control of the bike.
a. I'd like a more accurate power calculation, maybe based on a strain gauge/Prony brake idea, or by calculating spindown curves related to the inertia of the flywheel.
b. I'd like to control resistance (and maybe incline) from Zwift or maybe my own program. I'd love to be able to ride a gps route of my local trails or roads on the Proform. A Raspberry Pi 4 would probably be my starting solution, because I have one available and actually already have some Python I wrote that can communicate with Zwift. It should be possible to "inject" command codes into the RS485 line from the RPi (or from an arduino). There is bluetooth communication but it seems to be encrypted somehow and I can't take control of the bluetooth.

Some pipe dreams I have that I don't know how I would manage: replace the bars with some proper road drops and brake levers (I already modified the saddle), incorporate gear shifting into the brake levers, change the resistance from rare earth magnets to an electromagnet for more consistent resistance levels.

Stay tuned, I will hopefully make some progress in the next few weeks.
 

dgrekov

Joined Jan 8, 2023
15
@kilomotor sounds good. So I have a slightly different version of the bike ... I guess it's 2.0 so interestingly, it actually has the resistance settings in the handle bars, two buttons per side.

Bike Link

Looking at the pinout, I have a header with 4 wires going down to the control board, looks to be a similar RS485 line. The red line is on 9V DC, black is ground, other two wires are there.

I used an ESP8266 based Wemos D1 Mini clone that runs at 3.3V and a 3.3V based MAX3483 board. For now, sending the frames as you've outlined above does not make the control board react yet. However, I am not 100% confident in my wiring and or my sketch. Later today, I'll share some photos, wiring diagram and my sketch. I also want to hook up a rudimentary ociliscope (analog pin on an adruino) to see what the control board sends up to see if there is anything that I can use to understand if it's the same or similar board as yours.

My problem is that my console took a dive and is in a boot look, so I can't use it to record what it's sending.
 

kilomotor

Joined Jan 17, 2022
13
I've been browsing the internet and there are tens if not hundreds of different Proform Tour de France model bikes available. I'm lazy, so if I was designing a bike, I would use the same codes and lower control boards... but who knows what the engineers at Proform did!
Here is a picture of my control board. Of course, there is the possibility that different versions of firmware were loaded even on the same boards. There is what appears to be a serial header at the bottom but I haven't investigated that yet.
20230112_121252.jpg
@SunnyWideSky. I looked at the incline motor and you are indeed correct -- it counts revolutions with a hall effect sensor. If I unplug the sensor from the control board and change the incline on the console it will drive the motor to the position limit, probably because it is not getting feedback. Zeroing the incline is done by driving the motor to the max and min limits and then setting it in the middle. If the incline is changed and then the bike is turned off, it magically resets to the mid point at zero incline again. Does it save current position in flash memory? I don't know how it does this magic but will ponder this mystery. What happens to your incline if you disconnect the lower control board from the console? My bike zeros the resistance magnets but will not reset the incline (if the incline was changed, bike turned off, console unplugged and bike turned on again). until it receives communication from the console.

@dgrekov. I looked at your picture of your RS485 setup. It may be okay, it is a bit hard to follow all the wires in the picture. How are you sending a command to the lower control board? Make sure you have a ground from the RS485 to the bike ground line. In my setup I pressed a button and then the Arduino sent one command to the lower control board. I should mention that the incline commands don't work unless I am pedaling -- the bike keeps track of crank rpm with a reed switch. The adjustment for the "gears" is very subtle and one step might not be noticeable.
I have a simple sketch for Arduino that allows reading the values sent by the lower control board. The data lines are only 3.3v but my 5v Arduino can read the highs and lows without difficulty. I just connected the Arduinio RX pin to the blue data line and the Arduino GND to the bike black ground. A bit of code:
Code:
/*
 * Read bytes from the Proform Tour de France bike
 * and print them to the arduino console
 */

byte incoming = 0;

void setup() {
  delay(100);
  Serial.begin(38400);
}

void loop() {
  if (Serial.available() > 0)
  {
    incoming = Serial.read();
    Serial.print(incoming, HEX);  //print all the commands received
    if (incoming == 0x8A) //this is the end marker for a command
    {
      Serial.println(); //newline
    }
  }
}
And then I can listen to the messages the lower board sends back to the console.
The lower control board is mute unless it gets a command from the console. When I first power on the bike I get this from the lower board:

8A8A8A8A8A8A8AC8C5CCCCCF8D8A8A8A8A8A8A8A
(note that in a regular message, "8A" is the end byte of a line usually so I get a bunch of newlines from my code)

After sending this small bit of data, the lower board just sits there, waiting... mute... I presume it is the secondary and the console acts as the primary for communications. Sadly, I can't send RS485 commands and receive them and display them on the Arduino console... yet. I will wire up a second Arduino later and see if the lower control board responds to a garbage command from the Arduino.
Don't give up!
 

dgrekov

Joined Jan 8, 2023
15
Not giving up by a longshot, we will figure thois out!!! Here is a diagram of how I have this wired up. Couple of big things from your note, 1) the board is quiet unless talked to and 2) the adjustments don't apply unless you're spinning. I'm going to wire everything up and see if it's better with the bike in motion

Attached is my wiring diagram and sketch (I'm using software serial):

Bike control Panel_bb.png

C++:
#include <Arduino.h>
#include "LittleFS.h"

#include "WiFiManager.h"
#include "webServer.h"
#include "updater.h"
#include "fetch.h"
#include "configManager.h"
#include "dashboard.h"
#include "timeSync.h"

#include <SoftwareSerial.h>

void setGear(int gear);
void setIncline(int incline);

#define RXPin        D2  // Serial Receive pin
#define TXPin        D3  // Serial Transmit pin

//RS485 control
#define SERIAL_COMMUNICATION_CONTROL_PIN D0 // Transmission set pin
#define RS485_TX_PIN_VALUE HIGH
#define RS485_RX_PIN_VALUE LOW

SoftwareSerial RS485Serial;

int incline = 30; //(levels from -15 to +15 by half increments. Index for zero is 30)
int gear = 0;

//expanded gear ranges. Can the resistance go higher?
//is the resistance increase at higher incline due to mechanical adjustment or due to new codes sent.
//                       1,    2,    3,    4,    5,    6,    7,    8,    9,   10,   11,   12,   13,   14,   15,   16,   17,   18,   19,   20,   21,   22,   23,   24,   25,   26,   27,   28,   29,   30,   31,   32,   33,   34,   35,   36,   37,   38,   39,   40,   41,   42,   43,   44,   45,   46,   47,   48,   49,   50,   51,   52,   53,   54,   55,   56,   57,   58,   59,   60,   61
byte gearCommand1[] ={0xB0, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4};
byte gearCommand2[] ={0xC6, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xC1, 0xC2};
byte gearCommand3[] ={0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4};
byte gearCommand4[] ={0xB5, 0xB4, 0xB3, 0xB2, 0xB1, 0xB0, 0xC6, 0xC5, 0xC4, 0xC3, 0xC2, 0xC1, 0xB9, 0xB8, 0xB7, 0xB6, 0xB5, 0xB4, 0xB3, 0xB2, 0xB1, 0xB0, 0xC6, 0xC5, 0xC4, 0xC3, 0xC2, 0xC1, 0xB9, 0xB8, 0xB7, 0xB6, 0xB5, 0xB4, 0xB3, 0xB2, 0xB1, 0xB0, 0xC6, 0xC5, 0xC4, 0xC3, 0xC2, 0xC1, 0xB9, 0xB8, 0xB7, 0xB6, 0xB5, 0xB4, 0xB3, 0xB2, 0xB1, 0xB0, 0xC6, 0xC5, 0xC4, 0xC3, 0xC2, 0xC1, 0xB9};

/*
//these are the bytes for gear changes.
//bytes 12 to 15.  There could be more levels in between these, note the pattern of bytes for incline
//                       1,    2,    3,    4,    5,    6,    7,    8,    9,   10,   11,   12,   13,   14,   15,   16,   17,   18,   19,   20,   21,   22
byte gearCommand1[] ={0xB0, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB4, 0xB4, 0xB4, 0xB4};
byte gearCommand2[] ={0xC6, 0xB1, 0xB4, 0xB7, 0xC1, 0xC4, 0xB0, 0xB3, 0xB6, 0xB8, 0xC2, 0xC5, 0xB1, 0xB4, 0xB7, 0xC1, 0xC4, 0xC6, 0xB2, 0xB5, 0xB8, 0xC2};
byte gearCommand3[] ={0xB8, 0xB8, 0xB8, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB4, 0xB4, 0xB4};
byte gearCommand4[] ={0xB5, 0xB3, 0xB0, 0xC4, 0xC1, 0xB7, 0xB4, 0xB1, 0xC5, 0xC3, 0xB9, 0xB6, 0xB3, 0xB0, 0xC4, 0xC1, 0xB7, 0xB5, 0xB2, 0xC6, 0xC3, 0xB9};
*/
//these are the bytes for incline changes
//note that "0" is number 31 below and changes are 0.5 degree increments on the bike
//                           1,    2,    3,    4,    5,    6,    7,    8,    9,   10,   11,   12,   13,   14,   15,   16,   17,   18,   19,   20,   21,   22,   23,   24,   25,   26,   27,   28,   29,   30,   31,   32,   33,   34,   35,   36,   37,   38,   39,   40,   41,   42,   43,   44,   45,   46,   47,   48,   49,   50,   51,   52,   53,   54,   55,   56,   57,   58,   59,   60,   61   
byte inclineCommand1[] = {0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3};
byte inclineCommand2[] = {0xC6, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xC1, 0xC2};
byte inclineCommand3[] = {0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB7, 0xB7, 0xB7};
byte inclineCommand4[] = {0xB9, 0xB8, 0xB7, 0xB6, 0xB5, 0xB4, 0xB3, 0xB2, 0xB1, 0xB0, 0xC6, 0xC5, 0xC4, 0xC3, 0xC2, 0xC1, 0xB9, 0xB8, 0xB7, 0xB6, 0xB5, 0xB4, 0xB3, 0xB2, 0xB1, 0xB0, 0xC6, 0xC5, 0xC4, 0xC3, 0xC2, 0xC1, 0xB9, 0xB8, 0xB7, 0xB6, 0xB5, 0xB4, 0xB3, 0xB2, 0xB1, 0xB0, 0xC6, 0xC5, 0xC4, 0xC3, 0xC2, 0xC1, 0xB9, 0xB8, 0xB7, 0xB6, 0xB5, 0xB4, 0xB3, 0xB2, 0xB1, 0xB0, 0xC6, 0xC5, 0xC4};

String dataReceived;

void setup()
{
    // Serial.begin(38400);
    
    LittleFS.begin();
    GUI.begin();
    configManager.begin();
    WiFiManager.begin(configManager.data.projectName);
    timeSync.begin();
    dash.begin(500);

    dash.data.incline = incline;
    dash.data.gear = gear;

    pinMode(SERIAL_COMMUNICATION_CONTROL_PIN, OUTPUT);
    digitalWrite(SERIAL_COMMUNICATION_CONTROL_PIN, RS485_RX_PIN_VALUE);
    RS485Serial.begin(38400, SWSERIAL_8N1, RXPin, TXPin);   // set the data rate
    pinMode(LED_BUILTIN, OUTPUT);
    digitalWrite(LED_BUILTIN, LOW);
 
}

void loop()
{
    //software interrupts
    WiFiManager.loop();
    updater.loop();
    configManager.loop();
    dash.loop();
    //your code here
    
    if (RS485Serial.available()){
        dataReceived = RS485Serial.readString();
        Serial.print("Data received ");
        Serial.println(dataReceived);
        int str_len = dataReceived.length() + 1;
        dataReceived.toCharArray(dash.data.lastMessage, str_len);
        delay(10);
    }

    if (dash.data.inputGear != dash.data.gear) {
      dash.data.gear = dash.data.inputGear;
      digitalWrite(SERIAL_COMMUNICATION_CONTROL_PIN, RS485_TX_PIN_VALUE); // Now trasmit
      digitalWrite(LED_BUILTIN, HIGH);
      setGear(dash.data.gear);
      digitalWrite(LED_BUILTIN, LOW);
      digitalWrite(SERIAL_COMMUNICATION_CONTROL_PIN, RS485_RX_PIN_VALUE);
    }

    if (dash.data.inputIncline != dash.data.incline) {
      dash.data.incline = dash.data.inputIncline;
      digitalWrite(SERIAL_COMMUNICATION_CONTROL_PIN, RS485_TX_PIN_VALUE); // Now trasmit
      digitalWrite(LED_BUILTIN, HIGH);
      setIncline(dash.data.incline);
      digitalWrite(LED_BUILTIN, LOW);
      digitalWrite(SERIAL_COMMUNICATION_CONTROL_PIN, RS485_RX_PIN_VALUE);
    }
}


void setGear(int gear){
  RS485Serial.write(0xBA);
  RS485Serial.write(0xB6);
  RS485Serial.write(0xB1);
  RS485Serial.write(0xB0);
  RS485Serial.write(0xB6);
  RS485Serial.write(0xB0);
  RS485Serial.write(0xB0);
  RS485Serial.write(0xB0);
  RS485Serial.write(0xB5);
  RS485Serial.write(0xB0);
  RS485Serial.write(0xB0);
  RS485Serial.write(gearCommand1[gear]);
  RS485Serial.write(gearCommand2[gear]);
  RS485Serial.write(gearCommand3[gear]);
  RS485Serial.write(gearCommand4[gear]);
  RS485Serial.write(0x8D);
  RS485Serial.write(0x8A);
  delay(500);
}

void setIncline(int incline) {
  RS485Serial.write(0xBA);
  RS485Serial.write(0xB4);
  RS485Serial.write(0xB1);
  RS485Serial.write(0xB0);
  RS485Serial.write(0xB6);
  RS485Serial.write(0xB0);
  RS485Serial.write(0xB0);
  RS485Serial.write(0xB0);
  RS485Serial.write(0xB1);
  RS485Serial.write(0xB0);
  RS485Serial.write(0xB0);
  RS485Serial.write(inclineCommand1[incline]);
  RS485Serial.write(inclineCommand2[incline]);
  RS485Serial.write(inclineCommand3[incline]);
  RS485Serial.write(inclineCommand4[incline]);
  RS485Serial.write(0x8D);
  RS485Serial.write(0x8A);
  delay(500);
}
 

dgrekov

Joined Jan 8, 2023
15
Oh my god, that was it! With pedaling it worked. The resistance and incline changed as expected. We can try to figure out if there are further gears, as it seems like there was not THAT much resistance at level 60.

That being said, I wonder how the feedback back works in regards to speed, and other indicators ... as you've said the board is mainly silent. Maybe there is a way to requests status from the board? can anyone record messages that go across from the panel when a workout is ongoing?

BTW, my sketch is using ESP8266 IOT Framework that adds a dashboard, wifi and other helpful tools to the party.
 
Top