This project is inspired by the JWFFM modchip and unlocks battery expansion possibilities on otherwise locked Onewheels.
The authors and contributors of this project are in no way affiliated with Future Motion Inc. Onewheel, Onewheel XR, Onewheel Pint, Onewheel Plus, etc are registered trademarks of Future Motion Inc.
This is a hobby projet for its contributors and comes with absolutely no guarantees of any sorts. Messing with your Onewheel in any way voids its warranty and could potentially lead to property loss, injuries or even death. Don't be silly and use this project at your own risk.
- Unlocks battery expansion capabilities on Pints and XRs.
- Displays correct battery percentage in the official Onewheel app.
- Defeats BMS <-> Controller pairing and allows you to use any Pint or XR BMS in your board.
- Shows various stats about your battery on a web page through WiFi - Voltage, current, individual cell voltages and more.
- Supports future firmware updates via WiFi - no need to reopen your board.
- Have essential soldering skills and tools: Soldering iron, some 22 gauge or otherwise thin wires, fish tape or isolating tape.
- Be comfortable with opening your board's battery enclosure.
- For the PINT you require a somewhat exotic Torx 5 point security bit, size TS20. Amazon link
- For the XR+ you will need a 3/32" Allen key. Amazon link
- Wemos D1 Mini Lite - the cheapest and most compact ESP8266 board that I'm aware of. You can find those on Aliexpress and Amazon. Buy version without the metal shield or ceramic WiFi antenna on it as they're too bulky to fit inside of the battery enclosure. 5 pack Amazon Link.
- Click
Gitpod Ready-to-Code
button at the top of the readme, and connect with your github account - Once container is up, expand left menu .pio > d1_mini_lite_clone, and right click on firmware.bin -> download
- Use the ESP WebTools page provided here.
- Follow the instructions on that page to flash the firmware.
- Verify the flash success: When the chip is on, you should see
a WiFi network called
Owie-XXXX
. Connecting to it should send you straight to the status page of the Owie board. Don't worry about the data because the board isn't hooked up yet.
NEW: Follow this step-by-step installation video made by one of the community members - https://www.youtube.com/watch?v=HhKdwnYUbA0
Or follow these instructions below:
- Install Owie fimrware onto your Wemos D1 mini as instructed above.
- Disassemble your board and open the battery enclosure.
- Disconnect all wires from BMS, strictly in the following order:
- Battery balance lead - the leftmost connector (24 wires) on the BMS.
- Battery main lead - an XT60 connector on the rightmost side of the BMS.
- All the other wires to the BMS, the order here doesn't matter.
- Prepare your Wemos D1 Mini and BMS:
- Tin 4 consecutive pins on Wemos D1 Mini marked as TX, RX, D1, D2 as well as 5v, GND pins.
- Solder a small wire on the top of the board connecting the pin marked as TX to the pin marked as D2
- Solder power pickup wires to the BMS. The JWFFM chip installation video demonstrates this well - Youtube: Power pickup from BMS
- Cut the WHITE and GREEN wires from the three-wire connector around 3/4 of an inch from the connector. Wrap the Green wire leading to the BMS(the 3/4 inch stub) in an isolating wire as we won't be needing it. Tin the other three wire endings, you'll be soldering those to the Wemos D1 Mini. Again, JWFFM install video has a good demonstration of this: Youtube: Cutting GREEN and WHITE wires
- Connecting wires to your Wemos D1 Mini. I found it much easier to solder these to the bottom of the board:
- Connect the GROUND wire from the BMS, the middle wire out of the BMS 5 pin connector to GND on Wemos D1.
- Connect the 5v wire, the other one from BMS to the 5v on the board.
- Connect the WHITE wire RUNNING TO THE MAIN BOARD to the TX pin on the board.
- Connect the GREEN wire RUNNING TO THE MAIN BOARD to the D1 pin on the board.
- Connect the WHITE stubby wire running to the BMS to the RX pin on the board.
- Cover the bottom of the Wemos D1 mini with either fish tape or isolating tape so that non of the exposed soldering joints have any chance of contacting anything on the BMS. I also put a bunch of tape on the top of the board, just in case.
DONE!
If after installing OWIE into your board it reports that your battery is at 1% even though it shouldn't, plug your board into a charger. This problem occurs because the BMS goes through a state reset and doesn't know the status of the battery, and plugging the board into a charger corrects this issue by forcing the BMS (and controller potentially) to do a state check.
Pictures demonstrating soldering points on the board:
How it looks like in my setup:
Use these instructions to update your Owie installation over WiFi (OTA).
These instructions will work so long as you can connect to your regular Owie-XXXX
network.
-
Follow the instructions above for how to build Owie from source using gitpod (or grab a release binary if they're available).
-
Once you have your hands on a firmware.bin file, copy that binary onto your flashing device of choice (desktop, laptop, phone). Some phones might not let you select the binary, thus you will need to use a computer.
-
Bring that device close to your board, and ensure that your Onewheel has at least a few percent of battery left in the tank.
-
Connect to your normal Owie network
Owie-XXXX
, and navigate to your normal owie IP (192.168.4.1). -
You should see the Owie menu load as normal.
-
Append
/update
to your Owie IP, thus navigating to192.168.4.1/update
. -
You should see the ElegantOTA selection screen (as shown below) come up.
-
Leave the
Firmware
radio button selected (as shown below), and select your binary that you acquired in step 1, using theChoose File
button. -
The progress bar should go to 100%, and then stop responding, and your device will disconnect from the network. Don't worry, this is normal.
-
Either check for your normal Owie wifi network to come back online, or in the app you should see battery percentage being reported again. Once either of these things occur (preferrably both), you can restart your board to reset the error 16.
-
Connect to the normal owie network, and check that your update has worked.
-
Enjoy.
These instructions are for if you somehow manage to bungle flashing your wemos OTA. They are the last step you can reasonably take before having to remove the chip from your board and flash it using a USB cable.
-
Follow the instructions above for how to build Owie from source using gitpod (or grab a release binary if they're available).
-
Once you have your hands on a firmware.bin file, copy that binary onto your flashing device of choice (desktop, laptop, phone). Some phones might not let you select the binary, thus you will need to use a computer.
-
Bring that device close to your board, and ensure that your Onewheel has at least a few percent of battery left in the tank (don't have it plugged in though).
-
Power cycle the Onewheel 3 times (reboot it) in 10 seconds. Keeping your app connected can be useful here as once Owie makes it into recovery mode, your board will report an error 16 (don't worry, this is supposed to happen).
- On XR's your headlights will come on as normal, but after a few seconds they will dim and then totally turn off, followed by your power button light flashing rapidly to indicate that error 16.
-
Connect to the wifi network named Owie-Recovery, and navigate to your normal owie IP (192.168.4.1).
-
You should see the ElegantOTA selection screen (as shown below) come up.
-
Leave the
Firmware
radio button selected (as shown below), and select your binary that you acquired in step 1, using theChoose File
button. -
The progress bar should go to 100%, and then stop responding, and your device will disconnect from the network. Don't worry, this is normal.
-
Either check for your normal Owie wifi network to come back online, or in the app you should see battery percentage being reported again. Once either of these things occur (preferrably both), you can restart your board to reset the error 16.
-
Connect to the normal owie network, and check that your update has stuck.
-
Enjoy.
This is the OTA screen that you're looking for:
The BMS (Battery Management System) board, located in the battery side of the onewheel, communicates with the main board via RS485 protocol. Details that I've managed to discover so far:
- The communication is unidirectional. The data flows only from BMS to MB. It's 115200 baud, standard 8N1 framing.
- The RS485 bus signaling voltage seems to be 3.3v. This makes it possible to read the bus voltages directly via ESP8266 and doesn't require 5v -> 3.3v level shifting.
- Both ends of the RS485 bus are terminated properly - 120 ohm resistors across the A and B lines and pullup / pulldown resistors A and B lines correspondingly.
Technically, we'd need to use RS485 drivers such as MAX485 to intercept and retransmit bits on the line, however so far it seems like we can do away with them:
The A (high) line of the RS485 bus coming from the BMS can be read directly via hardware UART with a little care.
When the line isn't driven by the BMS transmitter, it hovers around 3.3v/2 = 1.6v due to the terminating resistors on the BMS side. 1.6v isn't a defined logic level for a GPIO pin so chances are we'll read spurious data. However, if we turn on the pullup resistor of the UART RX pin to which the A line is connected, the bus idle voltage gets pulled up to right above 3 volts, which is more than 0.75*VDD necessary for a logic 1 input, mentioned in ESP32 datasheet. This way the A wire from the BMS can be fed directly into the UART Rx pin and its logical state will read 1 at line idle, just as we want for UART communication.
Transmitting the data to the MB requires us to signal on two wires. The A wire of the RS485 can be connected directly to the output of a hardware UART. The B line must be inverse of the A line as RS485 uses differential signalling. I've achieved this by simply attaching a pin change interrupt to the UART TX pin and bitbanging the inverse value of this pin to the B line of the RS485.
The data frames sent by BMS are of the following general format:
- Preamble - 3 bytes, fixed:
FF 55 AA
- Message type - 1 byte. I've so far observed all values between
0
and0xD
, inclusive, except1
and0x10
- Message body - variable length but fixed based on the message type above.
- Checksum - last two bytes of the frame - simply sum of all of the bytes in the frame, including the preamble.
I've isolated all message parsing code in src/lib/bms/packet_parses.cpp
, the code should be self-explanatory.