├── requirements.txt ├── bafang-test.py ├── protocol.py └── README.md /requirements.txt: -------------------------------------------------------------------------------- 1 | construct==2.9.45 2 | future==0.17.1 3 | iso8601==0.1.12 4 | protocol==0.1.0 5 | pyserial==3.4 6 | PyYAML==5.4 -------------------------------------------------------------------------------- /bafang-test.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | from serial import Serial, SerialException 3 | from construct import Const 4 | from protocol import connect_cmd, read_cmd, info_message, basic_message, pedal_message, throttle_message 5 | from sys import platform 6 | from glob import glob 7 | 8 | 9 | def serial_ports(): 10 | """ Lists serial port names 11 | 12 | :raises EnvironmentError: 13 | On unsupported or unknown platforms 14 | :returns: 15 | A list of the serial ports available on the system 16 | """ 17 | if platform.startswith('win'): 18 | ports = ['COM%s' % (i + 1) for i in range(256)] 19 | elif platform.startswith('linux') or platform.startswith('cygwin'): 20 | # this excludes your current terminal "/dev/tty" 21 | ports = glob('/dev/tty[A-Za-z]*') 22 | elif platform.startswith('darwin'): 23 | ports = glob('/dev/tty.*') 24 | else: 25 | raise EnvironmentError('Unsupported platform') 26 | 27 | result = [] 28 | for port in ports: 29 | try: 30 | s = Serial(port) 31 | s.close() 32 | result.append(port) 33 | except (OSError, SerialException): 34 | pass 35 | return result 36 | 37 | #ser = serial.Serial('/dev/tty.usbserial-DJ005O71', 1200, timeout=1) 38 | ser = Serial(serial_ports()[0], 1200, timeout=1) 39 | #print(ser.name) 40 | 41 | def read_config(cm, answ_format): 42 | print(cm) 43 | ser.write(cm) 44 | ser.flush() 45 | sleep(1) 46 | answ = ser.read(100) 47 | print(answ) 48 | t = answ_format.parse(answ) 49 | print(t) 50 | 51 | read_config(connect_cmd.build( 52 | dict()), 53 | info_message) 54 | 55 | read_config(read_cmd.build( 56 | dict(command = 'BASIC')), 57 | basic_message) 58 | 59 | read_config(read_cmd.build( 60 | dict(command = 'PEDAL')), 61 | pedal_message) 62 | 63 | read_config(read_cmd.build( 64 | dict(command = 'THROTTLE')), 65 | throttle_message) 66 | 67 | ser.close() 68 | -------------------------------------------------------------------------------- /protocol.py: -------------------------------------------------------------------------------- 1 | from construct import Const,Struct,Enum,Bytes,Byte,Array,BitStruct,BitsInteger 2 | 3 | connect_cmd = Struct( 4 | 'connect_cmd' / Const(b"\x11\x51\x04\xB0\x05") 5 | ) 6 | 7 | 8 | read_cmd = Struct( 9 | 'read_cmd' / Const(b"\x11"), # read command 10 | 'command' / Enum(Byte, 11 | BASIC = 0x52, 12 | PEDAL = 0x53, 13 | THROTTLE = 0x54) 14 | ) 15 | 16 | write_cmd = Struct( 17 | 'write_cmd' / Const(b"\x16"), # write command 18 | 'command' / Enum(Byte, 19 | BASIC = 0x52, 20 | PEDAL = 0x53, 21 | THROTTLE = 0x54), 22 | 'data_length' / Byte, 23 | 'data' / Bytes(5) 24 | ) 25 | #Enum(Integer('data_length'), 26 | # BASIC = 24, 27 | # PEDAL = 11, 28 | # THROTTLE = 6) 29 | 30 | 31 | # 51 10 48 5a 58 54 53 5a 5a 36 32 32 32 30 31 31 01 14 1b 32 | info_message = Struct( 33 | 'info_message' / Byte, 34 | 'status' / Byte, 35 | 'manufacturer' / Bytes(4), 36 | 'model' / Bytes(4), 37 | 'HW-Version' / Bytes(2), 38 | 'FW-Version' / Bytes(4), 39 | 'Voltage' / Enum(Byte, 40 | VOLTAGE_24 = 0x00, 41 | VOLTAGE_36 = 0x01, 42 | VOLTAGE_48 = 0x02, 43 | VOLTAGE_60 = 0x03, 44 | VOLTAGE_24_48 = 0x04, 45 | VOLTAGE_24_60 = 0x05 46 | ), 47 | 'max_current' / Byte, 48 | 'checksum' / Byte 49 | ) 50 | 51 | basic_message = Struct( 52 | 'basic_message' / Const(b"\x52\x18"), 53 | 'low_battery_protect' / Byte, 54 | 'limited_current' / Byte, 55 | 'limit_current_levels' / Array(10,Byte), 56 | 'limit_speed_levels' / Array(10,Byte), 57 | 'wheel_diameter' / Enum(Byte, 58 | INCH_16 = 0x1F, 59 | INCH_16a = 0x20, 60 | INCH_17 = 0x21, 61 | INCH_17a = 0x22, 62 | INCH_18 = 0x23, 63 | INCH_18a = 0x24, 64 | INCH_19 = 0x25, 65 | INCH_19a = 0x26, 66 | INCH_20 = 0x27, 67 | INCH_20a = 0x28, 68 | INCH_21 = 0x29, 69 | INCH_21a = 0x2A, 70 | INCH_22 = 0x2B, 71 | INCH_22a = 0x2C, 72 | INCH_23 = 0x2D, 73 | INCH_23a = 0x2E, 74 | INCH_24 = 0x2F, 75 | INCH_24a = 0x30, 76 | INCH_25 = 0x31, 77 | INCH_25a = 0x32, 78 | INCH_26 = 0x33, 79 | INCH_26a = 0x34, 80 | INCH_27 = 0x35, 81 | INCH_27a = 0x36, 82 | SIZE_700C = 0x37, 83 | INCH_28 = 0x38, 84 | INCH_28a = 0x39, 85 | INCH_29 = 0x3A, 86 | INCH_29a = 0x3B, 87 | INCH_30 = 0x3C, 88 | INCH_30a = 0x3D 89 | ), 90 | 'Speedmeter' / BitStruct( 91 | 'Speedmeter_Model' / Enum(BitsInteger(2), 92 | EXTERNAL = 0b00, 93 | INTERNAL = 0b01, 94 | MOTORPHASE = 0b10 95 | ), 96 | 'Signals' / BitsInteger(6) 97 | ), 98 | 'Checksum' / Byte 99 | ) 100 | 101 | # 53 0b 03 ff ff 64 06 14 0a 19 08 14 14 27 102 | pedal_message = Struct( 103 | 'pedal_message' / Const(b"\x53\x0B"), 104 | 'pedal_type' / Enum(Byte, 105 | NONE = 0x00, 106 | DH_SENSOR_12 = 0x01, 107 | BB_SENSOR_32 = 0x02, 108 | DOUBLE_SIGNAL_24 = 0x03 109 | ), 110 | 'designated_assist' / Enum(Byte, 111 | MODE_0 = 0x00, 112 | MODE_1 = 0x01, 113 | MODE_2 = 0x02, 114 | MODE_3 = 0x03, 115 | MODE_4 = 0x04, 116 | MODE_5 = 0x05, 117 | MODE_6 = 0x06, 118 | MODE_7 = 0x07, 119 | MODE_8 = 0x08, 120 | MODE_9 = 0x09, 121 | DISPLAY = 0xFF 122 | ), 123 | 'speed_limit' / Byte, 124 | 'start_current' / Byte, 125 | 'slow_start_mode' / Byte, 126 | 'startup_degree' / Byte, 127 | 'work_mode' / Byte, 128 | 'time_of_stop' / Byte, 129 | 'current_decay' / Byte, 130 | 'stop_decay' / Byte, 131 | 'keep_current' / Byte, 132 | 'Checksum' / Byte 133 | ) 134 | 135 | # 54 06 0b 23 00 03 11 14 ac 136 | throttle_message = Struct( 137 | 'throttle_message' / Const(b"\x54\x06"), 138 | 'start_voltage' / Byte, # x * 100mV 139 | 'end_voltage' / Byte, # x * 100mV 140 | 'mode' / Enum(Byte, 141 | SPEED = 0x00, 142 | CURRENT = 0x01 143 | ), 144 | 'designated_assist' / Enum(Byte, 145 | MODE_0 = 0x00, 146 | MODE_1 = 0x01, 147 | MODE_2 = 0x02, 148 | MODE_3 = 0x03, 149 | MODE_4 = 0x04, 150 | MODE_5 = 0x05, 151 | MODE_6 = 0x06, 152 | MODE_7 = 0x07, 153 | MODE_8 = 0x08, 154 | MODE_9 = 0x09, 155 | DISPLAY = 0xFF 156 | ), 157 | 'speed_limited' / Byte, 158 | 'start_current' / Byte, 159 | 'Checksum' / Byte 160 | ) 161 | 162 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bafang-python 2 | This is an attempt to decipher the protocol which is used by Bafang Pedelec Motors like BBS01 or BBS02 and provide a python tool/library to communicate with these devices. 3 | 4 | This is a description of the reverse-engineered Bafang protocol. If not stated otherwise, all values have to be interpreted as hex values. 5 | 6 | Baudrate: 1200,8,N,1 7 | 8 | 9 | ## Command: Connect 10 | * **Send:** 0x11 0x51 0x04 0xB0 0x05 (0x05 = (0x51 + 0x04 + 0xB0) MOD 256) 11 | * **Response:** 0x51 0x10 0x48 0x5A 0x58 0x54 0x53 0x5A 0x5A 0x36 0x32 0x32 0x32 0x30 0x31 0x31 0x01 0x14 0x1B 12 | 13 | ### Response (description): 14 | 15 | * 00: 0x51 16 | * 01: 0x10 (Length?) 17 | * 02-05: Manufacturer in ASCII (0x48 0x5A 0x58 0x54 -> HZXT) 18 | * 06-09: Model in ASCII (0x53 0x5A 0x5A 0x36 -> SZZ6) 19 | * 10-11: HW Version in ASCII {10}.{11} (0x32 0x32 -> 2.2) 20 | * 12-15: FW Version in ASCII {12}.{13}.{14}.{15} (0x32 0x30 0x31 0x31 -> 2.0.1.1) 21 | * 16: Voltage 22 | * 0x00: 24V (18-22) 23 | * 0x01: 36V (28-32) 24 | * 0x02: 48V (38-43) 25 | * 0x03: 60V (48-55) 26 | * 0x04: 24V-48V (18-43) 27 | * else: 24V-60V (18-55) 28 | * 17: Max Current (0x14 -> 20) 29 | * 18: Checksum ? (0x1B) 30 | 31 | 32 | ## Command: Read Basic 33 | 34 | * **Send:** 0x11 0x52 35 | * **Response:** 0x52 0x18 0x1F 0x0F 0x00 0x1C 0x25 0x2E 0x37 0x40 0x49 0x52 0x5B 0x64 0x64 0x64 0x64 0x64 0x64 0x64 0x64 0x64 0x64 0x64 0x34 0x01 0xDF 36 | 37 | ### Response (description): 38 | 39 | * 00: 0x52 40 | * 01: 0x18 (Length?) 41 | * 02: Low Battery Protect (V) (0x1F -> 31) 42 | * 03: Limited Current (A) (0x0F -> 15) 43 | * 04: Limit Current (%) Assist0 (0x00 -> 0) 44 | * 05: Limit Current (%) Assist1 (0x1C -> 28) 45 | * 06: Limit Current (%) Assist2 (0x25 -> 37) 46 | * 07: Limit Current (%) Assist3 (0x2E -> 46) 47 | * 08: Limit Current (%) Assist4 (0x37 -> 55) 48 | * 09: Limit Current (%) Assist5 (0x40 -> 64) 49 | * 10: Limit Current (%) Assist6 (0x49 -> 75) 50 | * 11: Limit Current (%) Assist7 (0x52 -> 82) 51 | * 12: Limit Current (%) Assist8 (0x5B -> 91) 52 | * 13: Limit Current (%) Assist9 (0x64 -> 100) 53 | * 14: Limit Speed (%) Assist0 (0x64 -> 100) 54 | * 15: Limit Speed (%) Assist1 (0x64 -> 100) 55 | * 16: Limit Speed (%) Assist2 (0x64 -> 100) 56 | * 17: Limit Speed (%) Assist3 (0x64 -> 100) 57 | * 18: Limit Speed (%) Assist4 (0x64 -> 100) 58 | * 19: Limit Speed (%) Assist5 (0x64 -> 100) 59 | * 20: Limit Speed (%) Assist6 (0x64 -> 100) 60 | * 21: Limit Speed (%) Assist7 (0x64 -> 100) 61 | * 22: Limit Speed (%) Assist8 (0x64 -> 100) 62 | * 23: Limit Speed (%) Assist9 (0x64 -> 100) 63 | * 24: Wheel Diameter (Inch) (0x34) 64 | * 0x1F,0x20: 16" 65 | * 0x21,0x22: 17" 66 | * 0x23,0x24: 18" 67 | * 0x25,0x26: 19" 68 | * 0x27,0x28: 20" 69 | * 0x29,0x2A: 21" 70 | * 0x2B,0x2C: 22" 71 | * 0x2D,0x2E: 23" 72 | * 0x2F,0x30: 24" 73 | * 0x31,0x32: 25" 74 | * 0x33,0x34: 26" 75 | * 0x35,0x36: 27" 76 | * 0x37: 700C 77 | * 0x38: 28" 78 | * 0x39,0x3A: 29" 79 | * 0x3B,0x3C: 30" 80 | * 25: Speedmeter Model/Speedmeter Signal 01 81 | * Bits 1-2 (Model) 82 | * 00: External 83 | * 01: Internal 84 | * 10: Motorphase 85 | * Bits 3-6 (Speedmeter Signals) 86 | * 26: Checksum? 0xDF 87 | 88 | ## Command: Read Pedal 89 | * **Send:** 0x11 0x53 90 | * **Response:** 0x53 0x0B 0x03 0xFF 0xFF 0x64 0x06 0x14 0x0A 0x19 0x08 0x14 0x14 0x27 91 | 92 | ### Response (description): 93 | * 00: 0x53 94 | * 01: 0x0B (Length?) 95 | * 02: Pedal Type (0x03) 96 | * 0x00: None 97 | * 0x01: DH-Sensor-12 98 | * 0x02: BB-Sensor-32 99 | * 0x03: DoubleSignal-24 100 | * 03: Designated Assist (FF) 101 | * 0x00-0x09: Assist Mode No. 102 | * 0xFF: By Display's Command 103 | * 04: Speed Limit (FF) 104 | * 0x0F-0x28: Speed Limit in km/h 105 | * 0xFF: By Display's Command 106 | * 05: Start current in % (0x64 -> 100) 107 | * 0x00-0x64 108 | * 06: Slow-Start Mode (06 -> 6) 109 | * 0x01-0x08: Mode Number 110 | * 07: Startup Degree (Signal No.) (0x14 -> 20) 111 | * Integer: Number of Signal before start 112 | * 08: Work Mode (0x0A -> 10) 113 | * 0x0A-0x50: Angular Speed of pedal/wheel*10 114 | * 0xFF: Undetermined 115 | * 09: Time of Stop (0x19 -> 25) 116 | * Integer: *10ms 117 | * 10: Current Decay (0x08 -> 8) 118 | * 0x01-0x08: Current Decay 119 | * 11: Stop Decay (0x14 -> 20) 120 | * Integer: *10ms 121 | * 12: Keep Current in % (0x14 -> 20) 122 | * 13: Checksum ? (0x27) 123 | 124 | ## Command: Read Throttle 125 | * **Send:** 0x11 0x54 126 | * **Response:** 54 06 0B 23 00 03 11 14 AC 127 | 128 | ### Response (description): 129 | * 00: 0x54 130 | * 01: 0x06 (Length?) 131 | * 02: Start Voltage *100mv (0x0B -> 11) 132 | * 03: End Voltage *100mv (0x23 -> 35) 133 | * 04: Mode 134 | * 0x00: Speed 135 | * 0x01: Current 136 | * 05: Designated Assist (0x03 -> 3) 137 | * 0x00-0x09: Assist Mode No. 138 | * 0xFF: By Display's Command 139 | * 06: Speed Limited (14 - 20) 140 | * 0x0F-0x28: Speed Limit in km/h 141 | * 0xFF: By Display's Command 142 | * 07: Start Current in % (14 - 20) 143 | * 08: Checksum ? (0xAC) 144 | 145 | ## Command: Set Basic 146 | * **Send:** 0x16 0x52 0x24 3..26 147 | * **Response:** 0x52 0x24 148 | 149 | ### Response (description): 150 | * 00: 0x52 151 | * 01: Result Code 152 | * 0x00: Low Battery Protect Setting Error 153 | * 0x01: Limited Current Setting Error 154 | * 0x02: Limit Current Assist0 Error 155 | * 0x03: Limit Current Assist1 Error 156 | * 0x04: Limit Current Assist2 Error 157 | * 0x05: Limit Current Assist3 Error 158 | * 0x06: Limit Current Assist4 Error 159 | * 0x07: Limit Current Assist5 Error 160 | * 0x08: Limit Current Assist6 Error 161 | * 0x09: Limit Current Assist7 Error 162 | * 0x0A: Limit Current Assist8 Error 163 | * 0x0B: Limit Current Assist9 Error 164 | * 0x0C: Limit Speed Assist0 Error 165 | * 0x0D: Limit Speed Assist1 Error 166 | * 0x0E: Limit Speed Assist2 Error 167 | * 0x0F: Limit Speed Assist3 Error 168 | * 0x10: Limit Speed Assist4 Error 169 | * 0x11: Limit Speed Assist5 Error 170 | * 0x12: Limit Speed Assist6 Error 171 | * 0x13: Limit Speed Assist7 Error 172 | * 0x14: Limit Speed Assist8 Error 173 | * 0x15: Limit Speed Assist9 Error 174 | * 0x16: Speedmeter Setting Error 175 | * 0x17: Speedmeter Signal Setting Error 176 | * 0x18: Success 177 | 178 | ## Command: Set Pedal 179 | * **Send:** 0x16 0x53 0x11 3..13 14(Checksum) 180 | * **Response:** 0x53 0x24 181 | 182 | ### Response (description): 183 | * 00: 0x53 184 | * 01: Result Code (TODO) 185 | * 0x00: Low Battery Protect Setting Error 186 | * 0x01: Limited Current Setting Error 187 | * 0x02: Limit Current Assist0 Error 188 | * 0x03: Limit Current Assist1 Error 189 | * 0x04: Limit Current Assist2 Error 190 | * 0x05: Limit Current Assist3 Error 191 | * 0x06: Limit Current Assist4 Error 192 | * 0x07: Limit Current Assist5 Error 193 | * 0x08: Limit Current Assist6 Error 194 | * 0x09: Limit Current Assist7 Error 195 | * 0x0A: Limit Current Assist8 Error 196 | * 0x0B: Limit Current Assist9 Error 197 | * 0x0C: Limit Speed Assist0 Error 198 | * 0x0D: Limit Speed Assist1 Error 199 | * 0x0E: Limit Speed Assist2 Error 200 | * 0x0F: Limit Speed Assist3 Error 201 | * 0x10: Limit Speed Assist4 Error 202 | * 0x11: Limit Speed Assist5 Error 203 | * 0x12: Limit Speed Assist6 Error 204 | * 0x13: Limit Speed Assist7 Error 205 | * 0x14: Limit Speed Assist8 Error 206 | * 0x15: Limit Speed Assist9 Error 207 | * 0x16: Speedmeter Setting Error 208 | * 0x17: Speedmeter Signal Setting Error 209 | * 0x18: Success 210 | --------------------------------------------------------------------------------