ESPHome Heltec HTIT Tracker (TFT, GNSS, LoRa)

I recently got a Heltec HTIT Tracker based on ESP32S3 with a 0.96 160x80 TFT, multi-system GNSS and LoRa
https://docs.heltec.org/en/node/esp32/wireless_tracker/index.html
I was astonished that there was no ready-made ESPHome yaml around, so I started nearly from scratch with this device.

Because I took several loooooong evenings to get this done, I thought why not share here for others :slight_smile:

Most trickiest for me was the TFT display. It does not suffice to define the display model st7735 with spi. Looking up schematics I found that also 2 GPIOs are needed to turn the TFT on.

The gps part using uart was straight forward.
I have no interest in LoRa so this is not available in following esphome yaml.

The display shows GNSS data
20240629_163533

Full yaml config:

substitutions:
  name: "heltec-htit-tracker"
  friendly_name: ESPHome Heltec HTIT Tracker

esphome:
  name: ${name}
  friendly_name: ${friendly_name}
  name_add_mac_suffix: false
  platformio_options:
    board_build.flash_mode: dio
  project:
    name: esphome.web
    version: '1.0'

esp32: # Heltec HTIT Tracker v1.1 = ESP32-S3FN8
  board: esp32-s3-devkitc-1
  framework:
    type: arduino # gps requires arduino
    #type: esp-idf # recommended for variants of the ESP32 like this ESP32S3
    #sdkconfig_options:
    #  COMPILER_OPTIMIZATION_SIZE: y
    #  COMPILER_OPTIMIZATION_PERFORMANCE: y

# Enable logging
logger:
  level: DEBUG
  logs:
    component: ERROR
    ili9xxx: INFO
    uart_debug: DEBUG
    gps: DEBUG

# Enable Home Assistant API
api:

# Allow Over-The-Air updates
ota:
  - platform: esphome

# Allow provisioning Wi-Fi via serial
improv_serial:

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

  # Set up a wifi access point
  # ap: {}

# In combination with the `ap` this allows the user
# to provision wifi credentials to the device via WiFi AP.
# captive_portal:

dashboard_import:
  package_import_url: github://esphome/firmware/esphome-web/esp32s3.yaml@v2
  import_full_config: true

# Sets up Bluetooth LE (Only on ESP32) to allow the user
# to provision wifi credentials to the device.
esp32_improv:
  authorizer: none

# To have a "next url" for improv serial
web_server:

#############################################################
################## TFT display ##############################

font:
  - file: "gfonts://Roboto Mono" # https://fonts.google.com/specimen/Roboto+Mono
    id: my_font
    size: 20
color:
  - id: white
    red: 100%
    green: 100%
    blue: 100%
  - id: red
    red: 100%
    green: 0%
    blue: 0%
  - id: yellow
    red: 100%
    green: 100%
    blue: 0%

# see https://esphome.io/components/display/ili9xxx#ili9xxx
display:
  - platform: ili9xxx
    model: st7735
    id: st7735
    # from HT_st7735.h [1]
    # #define ST7735_DC_Pin    40 // schematics:   MTDO --- RS
    dc_pin: GPIO40
    # #define ST7735_REST_Pin  39 // schematics:   MTCK --- RES
    reset_pin: GPIO39
    # #define ST7735_CS_Pin    38 // schematics: GPIO38 --- CS
    cs_pin: GPIO38
    #define ST7735_IS_160X80 1
    #define ST7735_XSTART 1
    #define ST7735_YSTART 26
    #define ST7735_WIDTH  160
    #define ST7735_HEIGHT 80
    #define ST7735_ROTATION (ST7735_MADCTL_MY | ST7735_MADCTL_MV | ST7735_MADCTL_BGR)
    color_order: bgr # corresponds to ST7735_MADCTL_BGR
    invert_colors: true # usually you want text on black background
    dimensions:
      width: 160
      height: 80
      offset_width: 1
      offset_height: 26
    transform:
      swap_xy: true   # corresponds to ST7735_MADCTL_MV
      mirror_y: true  # corresponds to ST7735_MADCTL_MY
      mirror_x: false
    data_rate: 40MHz
    auto_clear_enabled: true # else text would draw over old text
    lambda: |-
      // Display the string "Hello World!" at [0,10]
      //it.print(0, 10, id(my_font), "Hello World!");
      // Display some GNSS values
      it.printf(0,  0, id(my_font), id(white), "Sats %.0f  ", id(htit_gnss_satellites).state);
      it.printf(0, 20, id(my_font), id(white), " LAT %.2f °", id(htit_gnss_latitude).state);
      it.printf(0, 40, id(my_font), id(white), "LONG %.2f °", id(htit_gnss_longitude).state);
      it.printf(0, 60, id(my_font), id(white), " ALT %.1f m", id(htit_gnss_altitude).state);

# display st7735 requires spi
spi:
  - id: spi_st7735
    # from HT_st7735.h [1]
    # #define ST7735_SCLK_Pin 41 // schematics: MTDI --- SCLK --- SCL
    clk_pin: GPIO41
    # #define ST7735_MOSI_Pin 42 // schematics: MTMS --- SDIN --- SDA
    mosi_pin: GPIO42
    #miso_pin: GPIOxx // not needed

# display st7735 requires 2 GPIOs set to HIGH to turn on TFT
switch:
  # from HT_st7735.h [1]
  # #define ST7735_LED_K_Pin 21
  - platform: gpio
    pin: GPIO21
    id: led_k_pin
    restore_mode: ALWAYS_ON
  # #define ST7735_VTFT_CTRL_Pin  3
  - platform: gpio
    pin: GPIO3 # it's safe to ignore_strapping_warning
    id: vtft_ctrl_pin # schematics: Vext_Ctrl
    restore_mode: ALWAYS_ON

######################################################
################## GNSS ##############################

uart: # GNSS requires Vext_Ctrl to be HIGH
  id: uart_gnss
  # it's safe to ignore: WARNING GPIO33/34 is used by the PSRAM interface on ESP32-S3R8 / ESP32-S3R8V and should be avoided on these models
  tx_pin: GPIO34 # schematics_ GPIO34 --- GNSS_RX --- RX (tx_pin of ESP = RX of GNSS chip)
  rx_pin: GPIO33 # schematics_ GPIO33 --- GNSS_TX --- TX (rx_pin of ESP = TX of GNSS chip)
  baud_rate: 115200
  debug:
    direction: BOTH
    dummy_receiver: false # true if no UART device component (=gps) is configured for the UART bus (yet)
    after:
      delimiter: "\n"
    sequence:
      - lambda: UARTDebug::log_string(direction, bytes);

gps:
  latitude:
    name: "Latitude"
    id: htit_gnss_latitude
  longitude:
    name: "Longitude"
    id: htit_gnss_longitude
  altitude:
    name: "Altitude"
    id: htit_gnss_altitude
  speed:
    name: "Speed"
    id: htit_gnss_speed
  course:
    name: "Course"
    id: htit_gnss_course
  satellites:
    name: "Satellites"
    id: htit_gnss_satellites
time:
  - platform: gps
    id: gnss_time

# Some helper functions to restart ESPHome from HA
button:
- platform: restart
  name: HTIT Restart
- platform: safe_mode
  name: HTIT Safe Mode Boot

######################################################
################## References ########################
# [1] https://github.com/HelTecAutomation/Heltec_ESP32/blob/35c3adf9261fa005714ab6227a02a0e1171d3a7f/src/HT_st7735.h