Skip to content

Improve UART-TTL wiring guidance: avoid UART0 (GPIO1/GPIO3), document BMS protocol selection #884

Description

@syssi

Summary

A recurring pattern across support issues (#841, #875, and others) shows that users fail to
get the UART-TTL (GPS port) connection working out of the box. Two root causes dominate:

  1. Interference from a USB-UART converter sharing UART0 (GPIO1/GPIO3)
  2. Serial logger output also written to UART0, corrupting the BMS data stream

Both issues are silent – the firmware compiles and flashes without errors, but the BMS
either stays silent or sends garbled data. Symptoms include Invalid header errors,
wildly wrong sensor values (cell voltages at ±100 V, temperatures at 1316 °C), or
complete silence on the bus.


Affected configuration files

This issue concerns only the UART-TTL (GPS port) setup. The following files are
affected:

File Note
esp32-example.yaml Primary ESP32 UART-TTL example
esp32-example-debug.yaml Extends esp32-example.yaml, adds UART debug output
esp32-example-multiple-devices.yaml Two BMS on UART2 (GPIO16/17) and UART1 (GPIO14/4)
esp8266-example.yaml Primary ESP8266 UART-TTL example
esp8266-example-debug.yaml Extends esp8266-example.yaml, adds UART debug output
esp32-ble-uart-hybrid-example.yaml Hybrid: reads via UART-TTL, controls via BLE

Do NOT confuse with

These setups use completely different transport layers and are not affected by the
GPIO1/GPIO3 problem described here:

File(s) Transport Why different
esp32-ble-*.yaml Bluetooth Low Energy No UART wiring at all
esp32-jk-pb-modbus-example.yaml / esp8266-jk-pb-modbus-example.yaml RS485 (real Modbus) JK-PB series only; uses RS485 transceiver chip, different physical layer
esp32-display-example.yaml / esp8266-display-example.yaml RS485 (display port) Taps into the display bus, not the GPS/UART-TTL port
esp32-active-balancer-example.yaml / esp8266-active-balancer-example.yaml UART-TTL (active balancer) Separate device, not a JK-BMS GPS port

Note on naming confusion: The jk_modbus component used in the UART-TTL examples
is not real Modbus RTU. It implements the JK-proprietary framing protocol that
happens to travel over a UART-TTL wire. The name is misleading but intentional within
this project. Real Modbus (RS485, JK-PB series) lives in the
jk-pb-modbus-example files.


Root cause

UART0 (GPIO1 = TXD, GPIO3 = RXD) is a shared resource

On virtually every ESP32/ESP8266 development board, UART0 is wired to the on-board
USB-UART bridge (CH340, CP2102, …). During normal operation this means:

  • The USB-UART converter is already electrically driving those pins from the host PC.
  • The ESPHome logger (default config) outputs its log stream to UART0.

Attaching the BMS to the same bus turns the connection into a three-way collision:
BMS frames, logger output, and USB converter traffic all fight on the same wire.


Platform-specific recommendations

ESP32 – use the GPIO matrix

The ESP32 contains a full GPIO matrix. Any of the three hardware UARTs (UART0, UART1,
UART2) can be routed to any GPIO. The component already defaults to GPIO16/GPIO17
(UART2), which is the right choice. Users just need to understand why they must not
change those to GPIO1/GPIO3.

The logger continues to write to UART0 (GPIO1/GPIO3) in the background, but since the
BMS is connected to UART2 (GPIO16/GPIO17) there is zero interference. No baud_rate: 0
hack is needed for the logger on ESP32.

Do not use GPIO1 or GPIO3 for the BMS connection on an ESP32.

ESP8266 – SoftwareSerial with logger disabled

The ESP8266 has only one hardware UART (UART0, GPIO1/GPIO3). There is no second hardware
UART that could be routed elsewhere. ESPHome therefore falls back to SoftwareSerial
when the configured pins differ from GPIO1/GPIO3.

SoftwareSerial at 115200 baud is tight on an 80 MHz single-core MCU. Occasional CRC
errors are expected but the connection is usable. The current example already uses
GPIO4/GPIO5. That is the correct choice.

Critically, the logger must be silenced because it would otherwise spam UART0 and
interfere even when the BMS is on different pins (the ESP8266 TXD output is always
GPIO1 unless explicitly disabled):

logger:
  baud_rate: 0   # REQUIRED on ESP8266 – disables serial log output

The current esp8266-example.yaml already includes this. It must stay there.


BMS-side protocol selection

The JK-BMS GPS/UART port must be configured with the correct protocol. Newer firmware
versions (≥ v18) show an explicit protocol selection screen on the BMS display.

Make sure the GPS port is set to RS485 / UART and not to a GPS or 4G modem
protocol. A wrong protocol setting on the BMS side produces the exact same symptoms as
a wiring problem: Invalid header: 0x4E 0x40, corrupted sensor readings, or silence.

Screenshot from issue #841 showing the protocol selection on the BMS display:

Image


Proposed documentation changes

  • Add a Troubleshooting subsection to the README under the Schematics block that
    explicitly calls out the UART0 / GPIO1/GPIO3 conflict.
  • Add a one-liner comment to esp32-example.yaml substitutions block explaining why
    GPIO16/GPIO17 is the safe default:
    yaml tx_pin: GPIO16 # Avoid GPIO1 (UART0/TXD) – shared with USB-UART converter and logger rx_pin: GPIO17 # Avoid GPIO3 (UART0/RXD) – shared with USB-UART converter and logger
  • Add a similar comment to esp8266-example.yaml and explicitly note that
    logger: baud_rate: 0 is not optional.
  • Verify that images/circuit.jpg does not show GPIO1/GPIO3 in the wiring diagram.
    If it does, update the image.
  • Mention the BMS-side protocol selection requirement in the Schematics / wiring
    section of the README.

References

  • JKBMS Hardware V18 #841 – Invalid header / corrupted data,
    solved by switching away from UART0 and setting correct BMS protocol
  • Changes in fw 19.27? #875 – No data after firmware upgrade,
    root cause traced to GPIO1/GPIO3 conflict with USB converter and logger

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions