TinyC — Custom Build Guide¶
Pre-built firmware is provided for ESP32 (4MB), ESP32-S3 (16MB), ESP32-C3 (4MB), and ESP8266 (4MB). For other ESP32 variants, build your own firmware using the configurations below.
Prerequisites¶
- PlatformIO installed (CLI or VS Code extension)
- Tasmota source tree cloned:
git clone https://github.com/gemu2015/Sonoff-Tasmota - No other
#define device_*active inuser_config_override.h
Required Defines¶
The TINYC_TESTING build flag (set via -DTINYC_TESTING in platformio) activates all
necessary defines in user_config_override.h. This includes:
// Core TinyC
#define USE_TINYC // TinyC VM (XDRV_124)
#define USE_TINYC_IDE // Browser IDE endpoint
// Hardware buses
#define USE_I2C // I2C bus
#define USE_SPI // SPI bus
#define USE_UFILESYS // Filesystem (required for IDE)
// Display (ESP32 only)
#define USE_DISPLAY // Display driver
#define USE_UNIVERSAL_DISPLAY // Universal display
#define USE_UNIVERSAL_TOUCH // Touch input
// Networking
#define USE_WEBCLIENT_HTTPS // HTTPS client (required for repo loading)
#define USE_WEBSEND_RESPONSE // Web response forwarding
#define USE_SENDMAIL // Email support
// Optional features
#define USE_SML_M // Smart meter interface
#define USE_DEEPSLEEP // Deep sleep support
#define USE_COUNTER // Pulse counter
#define USE_SUNRISE // Sunrise/sunset calculation
Note: TinyC has its own I2C, SPI, and serial implementations and does not require the
Tasmota Scripter engine. The -DTINYC_NO_SCRIPTER flag (included by default in all recommended
configurations below) excludes Scripter entirely, saving ~120 KB of flash.
Build Flags¶
| Flag | Effect | Default |
|---|---|---|
-DTINYC_TESTING |
Enable TinyC with all standard features | Required |
-DTINYC_NO_SCRIPTER |
Exclude Tasmota Scripter engine (~120 KB flash saved) | Recommended |
-DTINYC_HOMEKIT |
Enable Apple HomeKit support | All builds |
-DTINYC_CAMERA |
Enable integrated camera driver (ESP32/S3 only, not RISC-V) | ESP32/S3 builds |
-DTINYC_NO_DISPLAY |
Exclude display support (~80 KB flash saved) | Optional |
What's Included in Pre-Built Firmware¶
All pre-built firmware includes:
- HomeKit — Apple Home integration via -DTINYC_HOMEKIT
- Display — Universal display + touch support
- SML — Smart meter interface
- Email — SMTP with file/picture attachments
- I2C / SPI / Serial — Hardware bus access (native TinyC, no Scripter dependency)
ESP32 and ESP32-S3 builds additionally include:
- Camera — Integrated camera driver via -DTINYC_CAMERA (+34 KB). Supports OV2640, OV3660, OV5640 with MJPEG streaming, PSRAM slot management, and motion detection
ESP32-C3 (RISC-V) does not include camera support — the esp32-camera library requires Xtensa.
platformio_override.ini Sections¶
Add these sections to your platformio_override.ini. Each extends the TinyC base
configuration. Build with: pio run -e <environment-name>
Common Base (required)¶
[env:tinyc_base]
; Common TinyC build settings — inherits from tasmota32_base
; All builds get HomeKit + display, no Scripter
build_flags = ${env:tasmota32_base.build_flags}
-DTINYC_TESTING
-DTINYC_NO_SCRIPTER
-DTINYC_HOMEKIT
ESP32 (4MB) — with Camera¶
Classic ESP32 WROOM module. The standard build for most ESP32 devices.
[env:tinyc32-4M]
extends = env:tasmota32_base
board = esp32
board_build.f_cpu = 240000000L
board_build.partitions = partitions/esp32_partition_app1856k_fs1344k.csv
build_flags = ${env:tinyc_base.build_flags}
-DTINYC_CAMERA
lib_ignore = ${env:tasmota32_base.lib_ignore}
TTGO TWatch Library
Micro-RTSP
epdiy
lib_extra_dirs = ${common.lib_extra_dirs}
lib/libesp32
lib/libesp32_div
ESP32-S3 (16MB) — with Camera¶
Dual-core Xtensa S3 with 16MB flash. Default for S3 devkits.
[env:tinyc32s3]
extends = env:tasmota32_base
board = esp32s3_16M
board_build.f_cpu = 240000000L
board_build.mcu = esp32s3
build_flags = ${env:tinyc_base.build_flags}
-DTINYC_CAMERA
lib_ignore = ${env:tasmota32_base.lib_ignore}
TTGO TWatch Library
Micro-RTSP
epdiy
lib_extra_dirs = ${common.lib_extra_dirs}
lib/libesp32
lib/libesp32_div
ESP32-C3 (4MB) — no Camera¶
RISC-V single-core. Camera library not available (requires Xtensa).
[env:tinyc32c3]
extends = env:tasmota32_base
board = esp32c3
board_build.f_cpu = 160000000L
board_build.partitions = partitions/esp32_partition_app1856k_fs1344k.csv
build_flags = ${env:tinyc_base.build_flags}
lib_ignore = ${env:tasmota32_base.lib_ignore}
TTGO TWatch Library
Micro-RTSP
epdiy
lib/libesp32/CORE2_Library
libesp32_lvgl
esp32-camera
lib_extra_dirs = ${common.lib_extra_dirs}
lib/libesp32
lib/libesp32_div
Additional Variants¶
ESP32-S3 with USB CDC (DFRobot, native USB)¶
For boards with native USB (no UART chip), like DFRobot Firebeetle 2 ESP32-S3:
[env:tinyc32s3-usb]
extends = env:tinyc32s3
build_unflags = -DARDUINO_USB_MODE=0
-DARDUINO_USB_CDC_ON_BOOT=0
build_flags = ${env:tinyc_base.build_flags}
-DTINYC_CAMERA
-DARDUINO_USB_MODE=1
-DARDUINO_USB_CDC_ON_BOOT=1
-DUSE_USB_CDC_CONSOLE
ESP32-S3 Sunton (QIO/OPI, RGB Display)¶
For Sunton boards with PSRAM in OPI mode and RGB displays:
[env:tinyc32s3-sunton]
extends = env:tasmota32_base
board = esp32s3ser-qio_opi_120
board_build.f_cpu = 240000000L
board_build.mcu = esp32s3
build_flags = ${env:tinyc_base.build_flags}
lib_ignore = ${env:tasmota32_base.lib_ignore}
TTGO TWatch Library
Micro-RTSP
epdiy
lib_extra_dirs = ${common.lib_extra_dirs}
lib/libesp32
lib/libesp32_div
ESP32-S2 (4MB)¶
Single-core Xtensa, 4MB flash. Good for simple USB-connected devices.
[env:tinyc32s2]
extends = env:tasmota32_base
board = esp32s2
board_build.f_cpu = 240000000L
board_build.partitions = partitions/esp32_partition_app1856k_fs1344k.csv
build_flags = ${env:tinyc_base.build_flags}
lib_ignore = ${env:tasmota32_base.lib_ignore}
TTGO TWatch Library
Micro-RTSP
epdiy
lib/libesp32/CORE2_Library
libesp32_lvgl
esp32-camera
lib_extra_dirs = ${common.lib_extra_dirs}
lib/libesp32
lib/libesp32_div
ESP32-C6 (4MB)¶
RISC-V single-core with WiFi 6 and Zigbee/Thread. Same architecture as C3.
[env:tinyc32c6]
extends = env:tasmota32_base
board = esp32c6
board_build.f_cpu = 160000000L
board_build.partitions = partitions/esp32_partition_app1856k_fs1344k.csv
build_flags = ${env:tinyc_base.build_flags}
lib_ignore = ${env:tasmota32_base.lib_ignore}
TTGO TWatch Library
Micro-RTSP
epdiy
lib/libesp32/CORE2_Library
libesp32_lvgl
esp32-camera
lib_extra_dirs = ${common.lib_extra_dirs}
lib/libesp32
lib/libesp32_div
ESP32 Solo1 (4MB)¶
Single-core ESP32 (some Sonoff devices, ESP32-SOLO1 module).
[env:tinyc32solo1]
extends = env:tasmota32_base
board = esp32_solo1_4M
board_build.f_cpu = 160000000L
board_build.partitions = partitions/esp32_partition_app1856k_fs1344k.csv
build_flags = ${env:tinyc_base.build_flags}
-DTINYC_CAMERA
lib_ignore = ${env:tasmota32_base.lib_ignore}
TTGO TWatch Library
Micro-RTSP
epdiy
lib_extra_dirs = ${common.lib_extra_dirs}
lib/libesp32
lib/libesp32_div
ESP32-S3 (8MB)¶
Dual-core Xtensa with 8MB flash. Many devkits and modules use 8MB.
[env:tinyc32s3-8M]
extends = env:tasmota32_base
board = esp32s3_8M
board_build.f_cpu = 240000000L
board_build.mcu = esp32s3
build_flags = ${env:tinyc_base.build_flags}
-DTINYC_CAMERA
lib_ignore = ${env:tasmota32_base.lib_ignore}
TTGO TWatch Library
Micro-RTSP
epdiy
lib_extra_dirs = ${common.lib_extra_dirs}
lib/libesp32
lib/libesp32_div
ESP32-S3 (4MB)¶
Dual-core Xtensa S3 with only 4MB flash. Use optimized partition.
[env:tinyc32s3-4M]
extends = env:tasmota32_base
board = esp32s3_4M
board_build.f_cpu = 240000000L
board_build.mcu = esp32s3
board_build.partitions = partitions/esp32_partition_app1856k_fs1344k.csv
build_flags = ${env:tinyc_base.build_flags}
-DTINYC_CAMERA
lib_ignore = ${env:tasmota32_base.lib_ignore}
TTGO TWatch Library
Micro-RTSP
epdiy
lib_extra_dirs = ${common.lib_extra_dirs}
lib/libesp32
lib/libesp32_div
ESP32 (16MB)¶
Classic ESP32 with 16MB flash (e.g., ESP32-WROVER-E 16MB).
[env:tinyc32-16M]
extends = env:tasmota32_base
board = esp32_16M
board_build.f_cpu = 240000000L
build_flags = ${env:tinyc_base.build_flags}
-DTINYC_CAMERA
lib_ignore = ${env:tasmota32_base.lib_ignore}
TTGO TWatch Library
Micro-RTSP
epdiy
lib_extra_dirs = ${common.lib_extra_dirs}
lib/libesp32
lib/libesp32_div
E-Paper Variants (Legacy UDisplay)¶
For e-paper displays that require the legacy UDisplay library instead of UDisplay_legacy:
[env:tinyc32c3-epd]
extends = env:tinyc32c3
lib_ignore = Servo(esp8266)
ESP8266AVRISP
ESP8266LLMNR
ESP8266NetBIOS
ESP8266SSDP
SP8266WiFiMesh
Ethernet(esp8266)
GDBStub
TFT_Touch_Shield_V2
ESP8266HTTPUpdateServer
ESP8266WiFiMesh
EspSoftwareSerial
SPISlave
universal display Library
ArduinoOTA
TTGO TWatch Library
Micro-RTSP
epdiy
lib/libesp32/CORE2_Library
libesp32_lvgl
esp32-camera
[env:tinyc32s3-epd]
extends = env:tinyc32s3
lib_ignore = Servo(esp8266)
ESP8266AVRISP
ESP8266LLMNR
ESP8266NetBIOS
ESP8266SSDP
SP8266WiFiMesh
Ethernet(esp8266)
GDBStub
TFT_Touch_Shield_V2
ESP8266HTTPUpdateServer
ESP8266WiFiMesh
EspSoftwareSerial
SPISlave
universal display Library
ArduinoOTA
TTGO TWatch Library
Micro-RTSP
epdiy
Camera Support Notes¶
The -DTINYC_CAMERA flag enables the integrated TinyC camera driver, which provides:
- Board-specific pin configuration via cameraInit(pins[], ...)
- MJPEG stream server on port 81
- PSRAM slot management (up to 4 concurrent captures)
- Motion detection
- Direct sensor register access
Supported targets: ESP32 and ESP32-S3 (Xtensa). The esp32-camera library does not compile on RISC-V targets (C3, C6) — add esp32-camera to lib_ignore for those.
Size impact: Adding camera support adds ~34 KB to firmware size.
Camera boards tested: - AI-Thinker ESP32-CAM (OV2640) - Goouuu ESP32-S3-CAM (OV2640) - DFRobot Firebeetle 2 ESP32-S3 AI CAM DFR1154 (OV3660)
Camera pin definitions are in the TinyC source file (camera.tc, webcam_tinyc.tc), not in the firmware — any camera board can be used by defining the correct pin array.
Partition Tables¶
| Flash Size | Partition File | App Size | Filesystem | Notes |
|---|---|---|---|---|
| 4MB | esp32_partition_app1856k_fs1344k.csv |
1,856 KB | 1,344 KB | Recommended for 4MB with safeboot |
| 8MB | esp32_partition_app3904k_fs3392k.csv |
3,904 KB | 3,392 KB | 8MB with safeboot |
| 16MB | esp32_partition_app3904k_fs11584k.csv |
3,904 KB | 11,584 KB | 16MB with safeboot (default for S3-16M) |
For 4MB boards: the TinyC firmware is ~1,650 KB, leaving ~200 KB headroom in the 1,856 KB app partition. Without Scripter (-DTINYC_NO_SCRIPTER), firmware is ~120 KB smaller, giving more headroom.
Build Command¶
# Build a specific environment
pio run -e tinyc32-4M
# Build and upload via serial
pio run -e tinyc32-4M --target upload
# Build and upload via OTA
pio run -e tinyc32-4M --target upload --upload-port <device-ip>
OTA Partition Management¶
Devices in sealed housings without serial access can resize their partition layout
at runtime using the chkpt console command. This is useful when switching between
firmware versions of different sizes.
Commands¶
| Command | Effect |
|---|---|
chkpt |
List current partition table |
chkpt p |
Auto-pack: shrink app0 to firmware size + ~200 KB overhead, expand filesystem. Warning: all files on the filesystem are lost! |
chkpt p <KB> |
Set app0 to a specific size in KB (1024–3904), adjust filesystem accordingly. Warning: all files on the filesystem are lost! |
chkpt a1 |
Add 64 KB custom partition (for plugin drivers), taken from filesystem |
chkpt a2..a4 |
Add 128/192/256 KB custom partition |
chkpt r |
Remove custom partition, return space to filesystem |
Examples¶
# Device has app0=2880 KB, spiffs=256 KB — shrink app to gain filesystem:
chkpt p
→ app0=1856 KB, spiffs=1280 KB (firmware 1603 KB + 252 KB overhead)
# Need to flash a larger firmware later — expand app first:
chkpt p 2880
→ app0=2880 KB, spiffs=256 KB
# With custom plugin partition present — custom is always preserved:
chkpt p
→ app0=1856 KB, spiffs=1280 KB, custom=64 KB (unchanged at end of flash)
Notes¶
- The device reboots automatically after any partition change
- Filesystem (LittleFS) is formatted during resize — back up files first
- The custom partition (plugin drivers) is never moved or removed by
chkpt p - The
chkptinfrastructure is always compiled into TinyC firmware, no extra build flags needed - App size is aligned to 64 KB boundaries
chkpt prequires a safeboot partition — devices without safeboot are refused (no recovery if partition table gets corrupted)
After Flashing¶
- Upload
tinyc_ide.html.gzto the device filesystem via Consoles > Manage File System - Open
http://<device-ip>/tinyc_ide.htmlin a browser - Write code, press Ctrl+Enter to compile, Ctrl+Shift+Enter to run on device