Reading GNSS from UART returns nothing - how to debug

Hello,

I am newbie to ESP Home, did some leds and plugs only and decided to develop my own device tracker. My ultimate objective is to have a battery powered tracker in my ebike with accelerometer, alarm, CAN interface to switch off/on engine, temperature sensors and more. However, I am stuck at the very beginning.

I bought ESP32-S3 A7670E 4G Development Board from waveshare because it has a lot of stuff on board directly and struggle with the very first task: to read the GNSS over UART.

According to their website, it has TX and RX pins on GPIO17 and GPIO18.

So I proceed with this code I found in ESP documentation:

uart:
  id: sim_uart
  tx_pin: 17
  rx_pin: 18
  baud_rate: 115200

gps:
  latitude:
    name: "Latitude"
  longitude:
    name: "Longitude"
  altitude:
    name: "Altitude"

The result is:
image

I admit to try some AI LLM models for consultation, they never provide clear working code, however, some experiments narrowing down my problem pointed me to a suspicion that I do not receive any NMEA messages. UART sends AT commands somewhere but the board never responds. Therefore, I would like to begin with debugging of the problem.

Thanks! @Mahko_Mahko might like to help me

What do you see in the ESPHOME logs if you enable uart debug?

I have verbose logging, so the log is quite long, but the important part would be the following:

[20:53:03][V][sensor:043]: ‘Longitude’: Received new state -1.000000
[20:53:03][D][sensor:094]: ‘Longitude’: Sending state -1.00000 ° with 6 decimals of accuracy
[20:53:03][VV][api.service:140]: send_sensor_state_response: SensorStateResponse {
key: 2355190616
state: -1
missing_state: NO
}

Interestingly, if I switch the GPIO pins RX<>TX, I get the same.

Full log here BIOSPACE-PRAGUE - Synology DiskStation

Can you post the full uart part of your configuration please.

There is nothing more than what I shared already.

Then you should try to set up uart debug per my hints on other chat.

Just thinking whether the hardware is correctly assembled? Waveshare provide zero docs, but I guess that I should have the antenna connected and ensure the hardware switch is on. That’s it.
89DA3F13-231C-49C6-A773-3CF99921908B_4_5005_c

Looks like the code cannot be compiled:

INFO ESPHome 2024.12.4
INFO Reading configuration /config/esphome/cannondale-tracker.yaml...
Failed config

uart: [source /config/esphome/cannondale-tracker.yaml:36]
  - id: uart_bus
    tx_pin: 
      number: 17
      mode: 
        output: True
        input: False
        open_drain: False
        pullup: False
        pulldown: False
      inverted: False
      ignore_pin_validation_error: False
      ignore_strapping_warning: False
      drive_strength: 20.0
    rx_pin: 
      number: 18
      mode: 
        input: True
        output: False
        open_drain: False
        pullup: False
        pulldown: False
      inverted: False
      ignore_pin_validation_error: False
      ignore_strapping_warning: False
      drive_strength: 20.0
    baud_rate: 9600
    debug: 
      direction: BOTH
      dummy_receiver: True
      after: 
        delimiter: 
          - 0x7E
        bytes: 150
        timeout: 100ms
      sequence: 
        - then: 
            - 
              Couldn't find ID 'desk_height'. Please check you have defined an ID with that name in your configuration.
              lambda: !lambda |-
                UARTDebug::log_int(direction, bytes, ',');                 // Log the message as int. 
                UARTDebug::log_hex(direction, bytes, ',');                 // Log the message in hex.

I created a sensor for the ID ‘desk_height’ in your code and it returns “unknown” in home assistant. Or what was your point, where should I see the debug log from the code?

You need to understand the basics of ESPHome and then adapt the code.

Start with a good read of the debug uart page and work on setting up a minimal uart debugger with just logging of the messages.

Getting that set-up is a first step.

I can help a little later if you can’t work through it.

ok then, thanks for your time. I need just a code that would work on my tiny case of reading GNSS over UART. The result -1 means, no NMEA message is sent. So I added switching on of the GNSS to the on_boot section, but no result. If you can help me instead of tell me that I need to be on a different level, I would appreciate it. I am novice in ESP Home but this seems to be super easy configuration, which does not work.

  on_boot:
    - priority: -100
      then:
        - uart.write: "AT\r\n"
        - delay: 1s
        - uart.write: "AT+CGNSSPWR=1"
        - delay: 1s
        - uart.write: "AT+CGNSSTST=1"

So first step I think is to see if you can recieve some UART messages and see them in the ESPHome logs. Try this. You may need to adjust the baud_rate and/or maybe the after:

uart:
  baud_rate: 115200
  debug:
    direction: BOTH
    dummy_receiver: true
    after:
      delimiter: "\n"
    sequence:
      - lambda: UARTDebug::log_string(direction, bytes);

If you want to send uart you can do it a few ways - a UART button, or UART switch could be good for testing.

The device you have seems relatively complex to me and there is quite a lot of docs to get through…

I moved a bit, your help is appreciated!

  1. I created a lot of buttons sending AT commands I found in the documentation of A76xx
  2. I properly configured the UART according to the documentation of ESP32-S3
  3. When I send the AT command, I get echo, which probably means the device received my command and sent it back - uart is properly configured, however, the device does not respond on any command as expected (OK, GPS data etc…) or in case of device reset, it certainly does not reset itself.

GPS is receiving -1 on everything, I am not sure how it is written in ESP home but it seems to me that it is independent on UART because the number is received under any uart configurations when I was switching pins etc.

I did not figure out where the debug log should be found. I am looking to the log after compilation but there is no change after adding the code from the section “debug” of the “uart bus” page on ESP Home documentation. Should I look elsewhere?

Here is my current log:

INFO ESPHome 2024.12.4
INFO Reading configuration /config/esphome/cannondale-tracker.yaml...
WARNING GPIO3 is a strapping PIN and should only be used for I/O with care.
Attaching external pullup/down resistors to strapping pins can cause unexpected failures.
See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins
INFO Generating C++ source...
INFO Compiling app...
Processing cannondale-tracker (board: esp32-s3-devkitc-1; framework: arduino; platform: platformio/[email protected])
--------------------------------------------------------------------------------
HARDWARE: ESP32S3 240MHz, 320KB RAM, 8MB Flash
 - toolchain-riscv32-esp @ 8.4.0+2021r2-patch5 
 - toolchain-xtensa-esp32s3 @ 8.4.0+2021r2-patch5
Dependency Graph
|-- AsyncTCP-esphome @ 2.1.4
|-- WiFi @ 2.0.0
|-- FS @ 2.0.0
|-- Update @ 2.0.0
|-- ESPAsyncWebServer-esphome @ 3.2.2
|-- DNSServer @ 2.0.0
|-- ESPmDNS @ 2.0.0
|-- noise-c @ 0.1.6
|-- Wire @ 2.0.0
|-- TinyGPSPlus @ 1.0.2
Compiling .pioenvs/cannondale-tracker/src/main.cpp.o
Linking .pioenvs/cannondale-tracker/firmware.elf
RAM:   [=         ]  12.6% (used 41360 bytes from 327680 bytes)
Flash: [=====     ]  48.8% (used 896061 bytes from 1835008 bytes)
Building .pioenvs/cannondale-tracker/firmware.bin
Creating esp32s3 image...
Successfully created esp32s3 image.
esp32_create_combined_bin([".pioenvs/cannondale-tracker/firmware.bin"], [".pioenvs/cannondale-tracker/firmware.elf"])
Wrote 0xeadc0 bytes to file /data/build/cannondale-tracker/.pioenvs/cannondale-tracker/firmware.factory.bin, ready to flash to offset 0x0
esp32_copy_ota_bin([".pioenvs/cannondale-tracker/firmware.bin"], [".pioenvs/cannondale-tracker/firmware.elf"])
========================= [SUCCESS] Took 28.35 seconds =========================
INFO Successfully compiled program.
INFO Connecting to 192.168.2.185 port 3232...
INFO Connected to 192.168.2.185
INFO Uploading /data/build/cannondale-tracker/.pioenvs/cannondale-tracker/firmware.bin (896448 bytes)
Uploading: [============================================================] 100% Done...

INFO Upload took 8.66 seconds, waiting for result...
INFO OTA successful
INFO Successfully uploaded program.
INFO Starting log output from 192.168.2.185 using esphome API
INFO Successfully connected to cannondale-tracker @ 192.168.2.185 in 7.390s
INFO Successful handshake with cannondale-tracker @ 192.168.2.185 in 0.068s
[13:14:48][I][app:100]: ESPHome version 2024.12.4 compiled on Jan 21 2025, 13:14:07
[13:14:48][C][wifi:600]: WiFi:
[13:14:48][C][wifi:428]:   Local MAC: 18:8B:0E:CD:4D:48
[13:14:48][C][wifi:433]:   SSID: [redacted]
[13:14:48][C][wifi:436]:   IP Address: 192.168.2.185
[13:14:48][C][wifi:440]:   BSSID: [redacted]
[13:14:48][C][wifi:441]:   Hostname: 'cannondale-tracker'
[13:14:48][C][wifi:443]:   Signal strength: -71 dB ▂▄▆█
[13:14:48][C][wifi:447]:   Channel: 4
[13:14:48][C][wifi:448]:   Subnet: 255.255.255.0
[13:14:48][C][wifi:449]:   Gateway: 192.168.2.1
[13:14:48][C][wifi:450]:   DNS1: 192.168.2.131
[13:14:48][C][wifi:451]:   DNS2: 192.168.2.1
[13:14:48][C][logger:185]: Logger:
[13:14:48][C][logger:186]:   Level: DEBUG
[13:14:48][C][logger:188]:   Log Baud Rate: 115200
[13:14:48][C][logger:189]:   Hardware UART: USB_CDC
[13:14:48][C][i2c.arduino:071]: I2C Bus:
[13:14:48][C][i2c.arduino:072]:   SDA Pin: GPIO3
[13:14:48][C][i2c.arduino:073]:   SCL Pin: GPIO2
[13:14:48][C][i2c.arduino:074]:   Frequency: 50000 Hz
[13:14:48][C][i2c.arduino:086]:   Recovery: bus successfully recovered
[13:14:48][I][i2c.arduino:096]: Results from i2c bus scan:
[13:14:48][I][i2c.arduino:102]: Found i2c device at address 0x36
[13:14:48][C][uart.arduino_esp32:151]: UART Bus 0:
[13:14:48][C][uart.arduino_esp32:152]:   TX Pin: GPIO18
[13:14:48][C][uart.arduino_esp32:153]:   RX Pin: GPIO17
[13:14:48][C][uart.arduino_esp32:155]:   RX Buffer Size: 256
[13:14:48][C][uart.arduino_esp32:157]:   Baud Rate: 115200 baud
[13:14:48][C][uart.arduino_esp32:158]:   Data Bits: 8
[13:14:48][C][uart.arduino_esp32:159]:   Parity: NONE
[13:14:48][C][uart.arduino_esp32:160]:   Stop bits: 1
[13:14:48][C][max17048:033]: MAX17048:
[13:14:48][C][max17048:034]:   Address: 0x36
[13:14:48][C][max17048:035]:   Voltage (V) 'Battery voltage'
[13:14:48][C][max17048:035]:     Device Class: 'battery'
[13:14:48][C][max17048:035]:     State Class: 'measurement'
[13:14:48][C][max17048:035]:     Unit of Measurement: 'V'
[13:14:48][C][max17048:035]:     Accuracy Decimals: 3
[13:14:48][C][max17048:036]:   State of Charge (%) 'Battery level'
[13:14:48][C][max17048:036]:     Device Class: 'battery'
[13:14:48][C][max17048:036]:     State Class: 'measurement'
[13:14:48][C][max17048:036]:     Unit of Measurement: '%'
[13:14:48][C][max17048:036]:     Accuracy Decimals: 2
[13:14:48][C][max17048:037]:   Discharge Rate (%/hr) 'Battery discharge rate'
[13:14:48][C][max17048:037]:     Device Class: 'battery'
[13:14:48][C][max17048:037]:     State Class: 'measurement'
[13:14:48][C][max17048:037]:     Unit of Measurement: '%/h'
[13:14:48][C][uart.button:014]: UART Button 'Open GNSS data output'
[13:14:48][C][uart.button:014]: UART Button 'Warm restart GNSS'
[13:14:48][C][uart.button:014]: UART Button 'Get GPS fixed position'
[13:14:48][C][uart.button:014]: UART Button 'Get NMEA raw data 0.0'
[13:14:48][C][uart.button:014]: UART Button 'Get NMEA raw data 0.1'
[13:14:48][C][uart.button:014]: UART Button 'RESET MODULE'
[13:14:48][C][uart.button:014]: UART Button 'SCAN WIFI'
[13:14:48][C][captive_portal:089]: Captive Portal:
[13:14:48][C][mdns:116]: mDNS:
[13:14:48][C][mdns:117]:   Hostname: cannondale-tracker
[13:14:48][C][esphome.ota:073]: Over-The-Air updates:
[13:14:48][C][esphome.ota:074]:   Address: cannondale-tracker.local:3232
[13:14:48][C][esphome.ota:075]:   Version: 2
[13:14:48][C][esphome.ota:078]:   Password configured
[13:14:48][C][safe_mode:018]: Safe Mode:
[13:14:48][C][safe_mode:020]:   Boot considered successful after 60 seconds
[13:14:48][C][safe_mode:021]:   Invoke after 10 boot attempts
[13:14:48][C][safe_mode:023]:   Remain in safe mode for 300 seconds
[13:14:48][C][api:140]: API Server:
[13:14:48][C][api:141]:   Address: cannondale-tracker.local:6053
[13:14:48][C][api:143]:   Using noise encryption: YES
[13:14:52][D][sensor:094]: 'Latitude': Sending state -1.00000 ° with 6 decimals of accuracy
[13:14:52][D][sensor:094]: 'Longitude': Sending state -1.00000 ° with 6 decimals of accuracy
[13:14:52][D][sensor:094]: 'Altitude': Sending state -1.00000 m with 1 decimals of accuracy
[13:14:54][D][button:010]: 'Get GPS fixed position' Pressed.
[13:14:54][D][uart.button:010]: 'Get GPS fixed position': Sending data...
[13:14:54][D][uart_debug:158]: >>> "AT+CGPSINFO"
[13:14:54][D][uart_debug:158]: <<< "AT+CGPSINFO"
[13:14:59][D][button:010]: 'SCAN WIFI' Pressed.
[13:14:59][D][uart.button:010]: 'SCAN WIFI': Sending data...
[13:14:59][D][uart_debug:158]: >>> "AT+CWSTASCAN"
[13:14:59][D][uart_debug:158]: <<< "AT+CWSTASCAN"
[13:15:01][D][button:010]: 'Get NMEA raw data 0.0' Pressed.
[13:15:01][D][uart.button:010]: 'Get NMEA raw data 0.0': Sending data...
[13:15:01][D][uart_debug:158]: >>> "AT+CGNSSPORTSWITCH = 0,0"
[13:15:01][D][uart_debug:158]: <<< "AT+CGNSSPORTSWITCH = 0,0"
[13:15:02][D][button:010]: 'Get NMEA raw data 0.1' Pressed.
[13:15:02][D][uart.button:010]: 'Get NMEA raw data 0.1': Sending data...
[13:15:02][D][uart_debug:158]: >>> "AT+CGNSSPORTSWITCH = 0,1"
[13:15:02][D][uart_debug:158]: <<< "AT+CGNSSPORTSWITCH = 0,1"
[13:15:03][D][button:010]: 'Open GNSS data output' Pressed.
[13:15:03][D][uart.button:010]: 'Open GNSS data output': Sending data...
[13:15:03][D][uart_debug:158]: >>> "AT+CGNSSTST=1"
[13:15:03][D][uart_debug:158]: <<< "AT+CGNSSTST=1"
[13:15:04][D][button:010]: 'Power on the GNSS' Pressed.
[13:15:04][D][uart.button:010]: 'Power on the GNSS': Sending data...
[13:15:04][D][uart_debug:158]: >>> "AT+CGNSSPWR=1"
[13:15:04][D][uart_debug:158]: <<< "AT+CGNSSPWR=1"
[13:15:06][D][button:010]: 'RESET MODULE' Pressed.
[13:15:06][D][uart.button:010]: 'RESET MODULE': Sending data...
[13:15:06][D][uart_debug:158]: >>> "AT+CRESET"
[13:15:06][D][uart_debug:158]: <<< "AT+CRESET"
[13:15:12][D][sensor:094]: 'Latitude': Sending state -1.00000 ° with 6 decimals of accuracy
[13:15:12][D][sensor:094]: 'Longitude': Sending state -1.00000 ° with 6 decimals of accuracy
[13:15:12][D][sensor:094]: 'Altitude': Sending state -1.00000 m with 1 decimals of accuracy

My yaml:

esphome:
  name: cannondale-tracker
  friendly_name: Cannondale Tracker

external_components:
  - source: github://Option-Zero/esphome-components
    components: [max17048]

esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: arduino

# Enable logging
logger:
  level: DEBUG

# Enable Home Assistant API
api:
  encryption:
    key: "h00Nj97jCO4I9jDUmxIfcCHy0WpIXy9rocFsy+RfXKg="

ota:
  - platform: esphome
    password: "f32a9ac7d88a3f88a297e1884319fe67"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Cannondale-Tracker"
    password: "AoJdi85n0F9z"

captive_portal:

uart:
  rx_pin: 17
  tx_pin: 18
  baud_rate: 115200
  debug:
    direction: BOTH
    dummy_receiver: true
    after:
      delimiter: "\n"
    sequence:
      - lambda: UARTDebug::log_string(direction, bytes);
      
i2c:
  sda: GPIO3
  scl: GPIO2

sensor:
  - platform: max17048
    battery_voltage:
      name: Battery voltage
      id: batt_v
    battery_level:
      name: Battery level
      id: batt_pct
    rate:
      name: Battery discharge rate
      id: batt_discharge_rate

button:
  - platform: uart
    name: "Power on the GNSS"
    data: "AT+CGNSSPWR=1"
  - platform: uart
    name: "Open GNSS data output"
    data: "AT+CGNSSTST=1"
  - platform: uart
    name: "Warm restart GNSS"
    data: "AT+CGPSWARM"
  - platform: uart
    name: "Get GPS fixed position"
    data: "AT+CGPSINFO"
  - platform: uart
    name: "Get NMEA raw data 0.0"
    data: "AT+CGNSSPORTSWITCH = 0,0"
  - platform: uart
    name: "Get NMEA raw data 0.1"
    data: "AT+CGNSSPORTSWITCH = 0,1"

  - platform: uart  
    name: "RESET MODULE"
    data: "AT+CRESET"
  - platform: uart  
    name: "SCAN WIFI"
    data: "AT+CWSTASCAN"

gps:
  latitude:
    name: "Latitude"
  longitude:
    name: "Longitude"
  altitude:
    name: "Altitude"
1 Like

I’m wondering whether you might be better off first working through the provided device example demos (especially the ESP-IDF ones) to confirm your hardware is all set-up and working correctly with tested code before venturing into moving it to ESPHome?

I feel like the hardware interfaces and protocols between the various onboard hardware isn’t “obvious” (at least to me).

Anyone trying to support you here would need to read and develop a bit of understanding of your device, which would take them a little time.

I read the wiki from top to bottom, it helped me to implement the battery status sensor with help of one esp home recipe I found around.

However, ESP IDF is visibly advanced. I thought that ESP Home’s magic is in the simplicity of the implementation: nothing more than UART pins is not needed, the GPS component of ESP Home seems to be developed on the NMEA standards. Both in concert produce several sensors and voiala, everything else can be done in home assisstant. There’s literally nothing special that one has to know if it were developed as expected. Or am I wrong and ESP home is not about the simplicity for people like me?

UART pins are certainly on 17 and 18. All documentations (Waveshare, ESP32-S3) says the same. What more do I need to get GPS readings?