Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions .github/actions/build-esp/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ inputs:
description: 'ESP-IDF version to use'
required: false
default: 'v5.5.1'
idf_target:
description: 'ESP-IDF target to use (esp32, esp32s3)'
required: false
default: 'esp32'

runs:
using: 'composite'
Expand All @@ -30,13 +34,13 @@ runs:
uses: actions/cache@v4
with:
path: .ccache
key: ccache-${{ runner.os }}-esp32-${{ inputs.idf_version }}-${{ hashFiles('**/CMakeLists.txt', 'sdkconfig.defaults', 'dependencies.lock') }}
key: ccache-${{ runner.os }}-${{ inputs.idf_target }}-${{ inputs.idf_version }}-${{ hashFiles('**/CMakeLists.txt', 'sdkconfig.defaults', format('sdkconfig.defaults.{0}', inputs.idf_target), format('dependencies.lock.{0}', inputs.idf_target)) }}

- name: Cache managed components
uses: actions/cache@v4
with:
path: managed_components
key: managed_components-${{ runner.os }}-${{ hashFiles('dependencies.lock') }}
key: managed_components-${{ runner.os }}-${{ inputs.idf_target }}-${{ hashFiles(format('dependencies.lock.{0}', inputs.idf_target)) }}

- name: esp-idf build and merge firmware
shell: bash
Expand All @@ -45,7 +49,7 @@ runs:
IMAGE="espressif/idf:${{ inputs.idf_version }}"

docker run --rm -t \
-e IDF_TARGET="esp32" \
-e IDF_TARGET="${{ inputs.idf_target }}" \
-e IDF_CCACHE_ENABLE=1 \
-e CCACHE_DIR="/app/${{ github.repository }}/.ccache" \
-e GITHUB_ACTIONS=true \
Expand Down
23 changes: 17 additions & 6 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -112,21 +112,26 @@ jobs:
build_esp:
name: Build and archive ESP firmware
runs-on: ubuntu-latest
strategy:
matrix:
idf_target: [esp32, esp32s3]

steps:
- name: Checkout
uses: actions/checkout@v5
- name: Build ESP binaries
uses: ./.github/actions/build-esp
with:
idf_target: ${{ matrix.idf_target }}
- name: Archive build output artifacts
uses: actions/upload-artifact@v4
with:
name: merged-firmware
name: merged-firmware-${{ matrix.idf_target }}
path: build/merged-firmware.bin
compression-level: 0

build_simulator:
name: Build and archive simulator binary
name: Build and archive simulator binaries
timeout-minutes: 10
runs-on: ubuntu-latest
container: joined/sdl2:latest
Expand All @@ -138,7 +143,7 @@ jobs:
path: |
~/.cache/pip
~/.platformio/.cache
key: ${{ runner.os }}-pio-v2
key: pio-${{ runner.os }}-${{ hashFiles('platformio.ini') }}
- uses: actions/setup-python@v6
with:
python-version: '3.12'
Expand All @@ -147,9 +152,15 @@ jobs:
- name: Build PlatformIO Project
run: |
pio run
- name: Archive build output artifacts
- name: Archive 480x320 simulator build
uses: actions/upload-artifact@v4
with:
name: simulator_480x320
path: .pio/build/3248s035c/program
compression-level: 0
- name: Archive 800x480 simulator build
uses: actions/upload-artifact@v4
with:
name: simulator
path: .pio/build/emulator/program
name: simulator_800x480
path: .pio/build/8048s070c/program
compression-level: 0
38 changes: 36 additions & 2 deletions .vscode/c_cpp_properties.sample.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,48 @@
}
},
{
"name": "Simulator",
"name": "Simulator 3248s035c",
"cStandard": "c23",
"cppStandard": "c++23",
"defines": [
"PLATFORMIO=60118",
"USE_SDL",
"LV_CONF_INCLUDE_SIMPLE",
"LV_LVGL_H_INCLUDE_SIMPLE"
"LV_LVGL_H_INCLUDE_SIMPLE",
"SDL_HOR_RES=480",
"SDL_VER_RES=320"
],
"compilerPath": "/usr/bin/gcc",
"includePath": [
"${workspaceFolder}/esp/ui",
"${workspaceFolder}/simulator/src",
"${workspaceFolder}/simulator/include",
"${workspaceFolder}/.pio/libdeps/emulator/lv_drivers",
"${workspaceFolder}/.pio/libdeps/emulator/lvgl",
"${workspaceFolder}/.pio/libdeps/emulator/lvgl/src"
],
"browse": {
"limitSymbolsToIncludedHeaders": true,
"path": [
"${workspaceFolder}/esp/ui",
"${workspaceFolder}/simulator/src",
"${workspaceFolder}/simulator/include",
"${workspaceFolder}/.pio/libdeps/emulator/lvgl",
"${workspaceFolder}/.pio/libdeps/emulator/lvgl/src"
]
}
},
{
"name": "Simulator 8048s070c",
"cStandard": "c23",
"cppStandard": "c++23",
"defines": [
"PLATFORMIO=60118",
"USE_SDL",
"LV_CONF_INCLUDE_SIMPLE",
"LV_LVGL_H_INCLUDE_SIMPLE",
"SDL_HOR_RES=800",
"SDL_VER_RES=480"
],
"compilerPath": "/usr/bin/gcc",
"includePath": [
Expand Down
17 changes: 7 additions & 10 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

## Project Overview

SunTransit is an ESP32-based IoT project that displays Berlin public transport (BVG) departure information on Sunton 3.5" LCD displays. The project consists of three main components:
SunTransit is an ESP32-based IoT project that displays Berlin public transport (BVG) departure information on Sunton LCD displays.
The project consists of three main components:

1. **ESP32 Firmware** - ESP-IDF based C++ application
2. **React Frontend** - Web interface for configuration
Expand All @@ -27,12 +28,12 @@ SunTransit is an ESP32-based IoT project that displays Berlin public transport (
- `idf.py monitor` - Open serial monitor
- `idf.py flash monitor` - Flash and immediately start monitoring
- `idf.py menuconfig` - Configure project settings
- `pip install -r requirements.txt` - Install Python dependencies

### Simulator Development
- Install libsdl2 dependency: `sudo apt-get install libsdl2-dev`
- `pio run` - Build simulator (runs from project root, includes UI from `esp/ui/` directly)
- `pio run -t upload` - Build and run simulator
- `pio run -t upload -e 3248s035c` - Build and run simulator for 480x320px screen
- `pio run -t upload -e 8048s070c` - Build and run simulator for 800x480px screen

### Code Quality
- `clang-format -i esp/**/*.{c,cpp,h,hpp}` - Format C++ code
Expand All @@ -51,23 +52,19 @@ SunTransit is an ESP32-based IoT project that displays Berlin public transport (
- **Time Management** (`time.*`) - SNTP synchronization and timezone handling

### Frontend Structure (`frontend/` directory)
- React 18 SPA with Material-UI components
- React 19 SPA with Material-UI components
- Uses SWR for API state management
- TypeScript throughout
- Parcel v2.11.0 for bundling
- Parcel for bundling
- Automatically gzipped during build for ESP32 embedding

### Development Workflow Notes
- The frontend is built first and embedded into ESP32 firmware
- VSCode C++ extension conflicts require simulator to be separate workspace
- Copy `.vscode/c_cpp_properties.sample.json` to `.vscode/c_cpp_properties.json` for ESP-IDF development
- Pre-commit hooks enforce formatting and linting

### Hardware Target
- Sunton 3248S035C boards (ESP32 + 3.5" LCD)
- 480x320px ST7796 display controller
- GT911 touch controller
- 4MB flash with custom partition table
Sunton 3248S035C (ESP32 + 3.5" LCD 480x320px) and 8048S070C (ESP32-S3 + 7.0" LCD 800x480px)

### Memory and Performance Considerations
- LVGL configuration optimized for ESP32 memory constraints
Expand Down
6 changes: 3 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@ set(EXTRA_COMPONENT_DIRS esp)
# For the LCD/Touch initializers in `lcd.h`
idf_build_set_property(COMPILE_OPTIONS "-Wno-missing-field-initializers" APPEND)

# TODO Fix deprecated enum conversion warning
# Seems like it's fixed on `master`, but not in the latest release (v8.3)

# TODO The following should be handled via menuconfig, but they're missing in the KConfig
# TODO These cause warnings like:
# `warning: ignoring attribute 'section (".iram1.4")' because it conflicts with previous 'section (".iram1.1")' [-Wattributes]`
Expand All @@ -25,4 +22,7 @@ idf_build_set_property(COMPILE_OPTIONS "-DLV_ATTRIBUTE_TICK_INC=IRAM_ATTR" APPEN
# For the fonts
idf_build_set_property(COMPILE_OPTIONS "-DLV_LVGL_H_INCLUDE_SIMPLE" APPEND)

# Target-specific lockfile
idf_build_set_property(DEPENDENCIES_LOCK "dependencies.lock.${IDF_TARGET}")

project(suntransit)
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ An [ESP32](https://www.espressif.com/en/products/socs/esp32) project to monitor

## Features

- Based on Sunton [3248S035C](https://www.openhasp.com/0.7.0/hardware/sunton/esp32-3248s035/) boards (3.5", 480x320px). In the future, support for other boards is planned.
- Supports Sunton [3248S035C](https://www.openhasp.com/0.7.0/hardware/sunton/esp32-3248s035/) (3.5", 480x320px) and [8048S070C](https://www.openhasp.com/0.7.0/hardware/sunton/esp32-8048s0xx/) (7.0", 800x480px).
- WiFi 🛜 provisioning via the "ESP SoftAP Provisioning" app 📱
- Web based configuration
- Selection of station to show departures from (BVG)
Expand Down
6 changes: 3 additions & 3 deletions dependencies.lock → dependencies.lock.esp32
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ dependencies:
type: service
version: 1.1.3
espressif/esp_lvgl_port:
component_hash: e720c95cf0667554a204591bb5fade4655fb2990465557041200fa44b5bc7556
component_hash: a3db8fedba9f474dac24f1e0cd5bc5e560224e51bb5fa30bb2aa5470d49048db
dependencies:
- name: idf
require: private
Expand All @@ -72,7 +72,7 @@ dependencies:
source:
registry_url: https://components.espressif.com/
type: service
version: 2.6.0
version: 2.6.1
espressif/mdns:
component_hash: 3ec0af5f6bce310512e90f482388d21cc7c0e99668172d2f895356165fc6f7c5
dependencies:
Expand Down Expand Up @@ -101,6 +101,6 @@ direct_dependencies:
- espressif/esp_lvgl_port
- espressif/mdns
- idf
manifest_hash: 82a45dec557a424f3c86f9c60f44fb777ddfb5fc973db799d2d6b8f5d19baac8
manifest_hash: c7e0a3e71168efcfe4914077ad130cf2087cff65f10aee88a2b5081658952861
target: esp32
version: 2.0.0
76 changes: 76 additions & 0 deletions dependencies.lock.esp32s3
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
dependencies:
bblanchon/arduinojson:
component_hash: b1c2f0b0bc26969af19809cee80b220fb882481d59cc75f8e79ebceecdc69f06
dependencies: []
source:
registry_url: https://components.espressif.com/
type: service
version: 7.4.2
espressif/esp_lcd_touch:
component_hash: 779b4ba2464a3ae85681e4b860caa5fdc35801458c23f3039ee761bae7f442a4
dependencies:
- name: idf
require: private
version: '>=4.4.2'
source:
registry_url: https://components.espressif.com
type: service
version: 1.1.2
espressif/esp_lcd_touch_gt911:
component_hash: acc1c184358aa29ef72506f618c9c76a8cc2bf12af38a2bff3d44d84f3a08857
dependencies:
- name: espressif/esp_lcd_touch
registry_url: https://components.espressif.com
require: public
version: ^1.1.0
- name: idf
require: private
version: '>=4.4.2'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.1.3
espressif/esp_lvgl_port:
component_hash: a3db8fedba9f474dac24f1e0cd5bc5e560224e51bb5fa30bb2aa5470d49048db
dependencies:
- name: idf
require: private
version: '>=4.4'
- name: lvgl/lvgl
registry_url: https://components.espressif.com
require: public
version: '>=8,<10'
source:
registry_url: https://components.espressif.com/
type: service
version: 2.6.1
espressif/mdns:
component_hash: 3ec0af5f6bce310512e90f482388d21cc7c0e99668172d2f895356165fc6f7c5
dependencies:
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.8.2
idf:
source:
type: idf
version: 5.5.1
lvgl/lvgl:
component_hash: b702d642e03e95928046d5c6726558e6444e112420c77efa5fdb6650b0a13c5d
dependencies: []
source:
registry_url: https://components.espressif.com
type: service
version: 9.3.0
direct_dependencies:
- bblanchon/arduinojson
- espressif/esp_lcd_touch_gt911
- espressif/esp_lvgl_port
- espressif/mdns
- idf
manifest_hash: c7e0a3e71168efcfe4914077ad130cf2087cff65f10aee88a2b5081658952861
target: esp32s3
version: 2.0.0
11 changes: 10 additions & 1 deletion esp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
file(GLOB_RECURSE FONT_SRCS ui/fonts/*.c)

# Select LCD implementation based on target
if(IDF_TARGET STREQUAL "esp32")
set(LCD_IMPL "lcd_3248s035c.cpp")
elseif(IDF_TARGET STREQUAL "esp32s3")
set(LCD_IMPL "lcd_8048s070c.cpp")
else()
message(FATAL_ERROR "Unsupported target: ${IDF_TARGET}")
endif()

idf_component_register(
SRCS "nvs_engine.cpp" "utils.cpp" "bvg_api_client.cpp" "lcd.cpp" "main.cpp" "http_server.cpp" "ui/ui.cpp" "time.cpp" ${FONT_SRCS}
SRCS "nvs_engine.cpp" "utils.cpp" "bvg_api_client.cpp" ${LCD_IMPL} "main.cpp" "http_server.cpp" "ui/ui.cpp" "time.cpp" ${FONT_SRCS}
INCLUDE_DIRS "." "ui"
PRIV_REQUIRES esp_app_format esp_http_client esp_http_server esp_timer esp_wifi json nvs_flash spiffs vfs wifi_provisioning lwip
)
Expand Down
17 changes: 14 additions & 3 deletions esp/idf_component.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
## IDF Component Manager Manifest File
targets:
- esp32
- esp32s3

dependencies:
bblanchon/arduinojson: "^7.0.0"

espressif/mdns: "^1.2.1"
espressif/esp_lcd_st7796: "^1.0.0"

espressif/esp_lcd_st7796:
version: "^1.0.0"
rules:
- if: target == "esp32"

espressif/esp_lcd_touch_gt911: "^1.0.7~1"

espressif/esp_lvgl_port: "^2.6.0"
## Required IDF version

idf:
version: ">=4.1.0"
version: ">=5.5.1"
2 changes: 1 addition & 1 deletion esp/lcd.cpp → esp/lcd_3248s035c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#include <freertos/task.h>
#include <mutex>

#include "lcd.hpp"
#include "lcd_3248s035c.hpp"

/* LCD size */
#define LCD_ST7796_H_RES (480)
Expand Down
3 changes: 3 additions & 0 deletions esp/lcd_3248s035c.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

#include "lcd_common.hpp"
Loading