Hi there, I just finished a good working config for the Sunton esp32 8048s70c, Cheap 7" touchscreen. Basically a Box3 clone based on lvgl.
esphome:
name: wallpanel
friendly_name: Wallpanel
platformio_options:
build_flags: "-DBOARD_HAS_PSRAM"
board_build.esp-idf.memory_type: qio_opi
board_build.flash_mode: dio
board_upload.maximum_ram_size: 524288
esp32:
board: esp32-s3-devkitc-1
variant: esp32s3
flash_size: 16MB
framework:
type: esp-idf
# Required to achieve sufficient PSRAM bandwidth
sdkconfig_options:
COMPILER_OPTIMIZATION_SIZE: y
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: y
CONFIG_ESP32S3_DATA_CACHE_64KB: y
CONFIG_ESP32S3_DATA_CACHE_LINE_64B: y
CONFIG_SPIRAM_FETCH_INSTRUCTIONS: y
CONFIG_SPIRAM_RODATA: y
CONFIG_ESPTOOLPY_FLASHSIZE_16MB: y # fix warning about 2mb found
psram:
mode: octal
speed: 80MHz
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "qI3Jiy8ILejyQU1eyspzMsAPdRjG/dhUYMtlNQVggF4="
ota:
- platform: esphome
password: "7e097303fc5a5f885464acb718a72782"
id: ota_esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
on_connect:
- delay: 5s # Gives time for improv results to be transmitted
- ble.disable:
on_disconnect:
- ble.enable:
- lvgl.page.show: no_wifi_page_lvgl
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Wallpanel Fallback Hotspot"
password: "7xzWoZo8ib8H"
improv_serial:
esp32_improv:
authorizer: none
captive_portal:
i2s_audio:
- id: audio_out
i2s_lrclk_pin: 18
i2s_bclk_pin: 0
- id: audio_in
i2s_lrclk_pin: 13 # WS für Mikrofon
i2s_bclk_pin: 12 # BCLK für Mikrofon
i2c:
sda: 19
scl: 20
scan: true
display:
- id: s3_box_lcd
platform: rpi_dpi_rgb
dimensions:
width: 800
height: 480
color_order: RGB
invert_colors: true
de_pin: 41
hsync_pin: 39
vsync_pin: 40
pclk_pin: 42
pclk_frequency: 12MHz # unsure about this
data_pins:
red:
- 14
- 21
- 47
- 48
- 45
green:
- 9
- 46
- 3
- 8
- 16
- 1
blue:
- 15
- 7
- 6
- 5
- 4
update_interval: never
auto_clear_enabled: false
lvgl:
top_layer:
widgets:
- button:
id: timer_bg
align: TOP_MID
hidden: true
width: 200
height: 100
bg_color: black
widgets:
- label:
id: timer_label
text: "00:00"
align: CENTER
text_color: white
text_font: font_timer
- bar:
id: timer_bar
width: 800
height: 20
animated: true
max_value: 100
anim_time: 300ms
bg_opa: TRANSP
value: 0
indicator:
bg_color: green
align: BOTTOM_LEFT
hidden: true
- button:
id: timer_stop
x: 120
y: 200
hidden: true
bg_color: red
checkable: true
width: 100
height: 50
widgets:
- label:
align: center
text: "Stop"
text_color: black
on_value:
- switch.turn_off: timer_ringing
buffer_size: 60%
pages:
- id: idle_page_lvgl
bg_color: 0x000000
on_long_press:
- switch.toggle: mute
widgets:
- image:
align: CENTER
src: casita_idle
- id: listenig_page_lvgl
widgets:
- image:
align: CENTER
src: casita_listening
- id: replying_page_lvgl
widgets:
- animimg:
align: CENTER
src: [ casita_replying, casita_listening ]
duration: 500ms
- label:
align: TOP_LEFT
width: 780
pad_top: 20
id: request
recolor: true
text: text_request
text_font: font_request
- label:
align: BOTTOM_LEFT
width: 780
id: response
recolor: true
pad_bottom: 20
text: text_response
text_font: font_response
- id: thinking_page_lvgl
widgets:
- image:
align: CENTER
src: casita_thinking
- id: error_page_lvgl
bg_color: 0x000000
widgets:
- image:
align: CENTER
src: casita_error
- id: no_ha_page_lvgl
bg_color: black
widgets:
- image:
align: CENTER
src: error_no_ha
- id: no_wifi_page_lvgl
widgets:
- image:
align: CENTER
src: error_no_wifi
- id: initializing_page_lvgl
bg_color: 0x000000
widgets:
- image:
align: CENTER
src: casita_initializing
- id: timer_finished_page_lvgl
widgets:
- image:
align: CENTER
src: casita_timer_finished
on_press:
- switch.turn_off: timer_ringing
touchscreen:
platform: gt911
id: main_touchscreen
address: 0x5D
update_interval: 16ms
transform:
mirror_x: true
swap_xy: true
speaker:
- platform: i2s_audio
i2s_audio_id: audio_out
dac_type: external
i2s_dout_pin: 17
id: box_speaker
buffer_duration: 600ms
media_player:
- platform: speaker
name: jarvis_player
id: speaker_media_player
announcement_pipeline:
speaker: box_speaker
num_channels: 1
files:
- id: timer_finished_wave_file
file: sound/timer_finished.wav
on_announcement:
- if:
condition:
microphone.is_capturing:
then:
- voice_assistant.stop:
on_idle:
- voice_assistant.start_continuous
microphone:
- platform: i2s_audio
id: box_microphone
i2s_audio_id: audio_in
adc_type: external
i2s_din_pin: 11
channel: left
sample_rate: 16000
bits_per_sample: 16bit
output:
- id: backlight_output
platform: ledc
pin: 2
light:
- platform: monochromatic
id: led
name: Screen
icon: "mdi:television"
entity_category: config
output: backlight_output
restore_mode: RESTORE_DEFAULT_ON
default_transition_length: 250ms
voice_assistant:
id: va
microphone: box_microphone
speaker: box_speaker
use_wake_word: true
noise_suppression_level: 2
#vad_threshold: 3
auto_gain: 24dBFS
volume_multiplier: 3.0
on_start:
- lvgl.page.show: idle_page_lvgl
on_listening:
then:
- lvgl.page.show: listenig_page_lvgl
on_idle:
- lvgl.page.show: idle_page_lvgl
on_stt_vad_end:
- lvgl.page.show: thinking_page_lvgl
on_stt_end:
- lvgl.widget.enable: request
- lvgl.label.update:
id: request
text: !lambda return x;
on_tts_start:
- lvgl.widget.enable: response
- lvgl.label.update:
id: response
text: !lambda return x;
on_tts_stream_start:
then:
- lvgl.page.show: replying_page_lvgl
on_tts_stream_end:
then:
- wait_until:
speaker.is_stopped
- lvgl.page.show: idle_page_lvgl
- lvgl.widget.disable: response
- lvgl.widget.disable: request
on_end:
- wait_until:
and:
- not:
media_player.is_announcing:
- not:
voice_assistant.is_running:
- lvgl.page.show: idle_page_lvgl
on_error:
- then:
- lvgl.page.show: error_page_lvgl
- delay: 5s
- lvgl.page.show: idle_page_lvgl
on_client_connected:
- wait_until:
not: ble.enabled
- voice_assistant.start_continuous:
- lvgl.page.show: idle_page_lvgl
on_client_disconnected:
- lvgl.page.show: error_page_lvgl
on_timer_started:
- lvgl.widget.show:
- timer_bg
- timer_bar
on_timer_cancelled:
- lvgl.widget.hide:
- timer_bg
- timer_bar
on_timer_tick:
- lvgl.label.update:
id: timer_label
text: !lambda |-
if (timers.empty()) return std::string("00:00");
auto timer = timers[0];
int minutes = timer.seconds_left / 60;
int seconds = timer.seconds_left % 60;
char buffer[6];
snprintf(buffer, sizeof(buffer), "%02d:%02d", minutes, seconds);
return std::string(buffer);
- lvgl.bar.update:
id: timer_bar
value: !lambda |-
if (timers.empty()) return 0;
auto timer = timers[0];
if (timer.total_seconds == 0) return 0;
return static_cast<int>(100.0 * timer.seconds_left / timer.total_seconds);
on_timer_finished:
- lvgl.widget.hide:
- timer_bg
- timer_bar
- switch.turn_on: timer_ringing
- lvgl.widget.show: timer_stop
- lvgl.page.show: timer_finished_page_lvgl
- while:
condition:
switch.is_on: timer_ringing
then:
- media_player.speaker.play_on_device_media_file:
media_file: timer_finished_wave_file
announcement: true
- wait_until:
media_player.is_announcing:
- wait_until:
not:
media_player.is_announcing:
switch:
- platform: template
id: timer_ringing
optimistic: true
restore_mode: ALWAYS_OFF
on_turn_off:
# Stop playing the alarm
- media_player.stop:
announcement: true
- lvgl.widget.hide: timer_stop
- lvgl.page.show: idle_page_lvgl
on_turn_on:
# Turn on the repeat mode and pause for 1000 ms between playlist items/repeats
- delay: 15min
- switch.turn_off: timer_ringing
- lvgl.page.show: idle_page_lvgl
- platform: template
name: Mute
id: mute
icon: "mdi:microphone-off"
optimistic: true
restore_mode: RESTORE_DEFAULT_OFF
entity_category: config
on_turn_off:
- if:
condition:
not:
- voice_assistant.is_running
then:
- voice_assistant.start_continuous
- light.turn_on: led
- lvgl.page.show: idle_page_lvgl
on_turn_on:
- voice_assistant.stop
- light.turn_off: led
- lvgl.page.show: idle_page_lvgl
image:
- file: image/error_320_240.png
id: casita_error
resize: 640x480
type: RGB565
transparency: alpha_channel
- file: image/idle_320_240.png
id: casita_idle
resize: 640x480
type: RGB565
transparency: alpha_channel
- file: image/listening_320_240.png
id: casita_listening
resize: 640x480
type: RGB565
transparency: alpha_channel
- file: image/thinking_320_240.png
id: casita_thinking
resize: 640x480
type: RGB565
transparency: alpha_channel
- file: image/replying_320_240.png
id: casita_replying
resize: 640x480
type: RGB565
transparency: alpha_channel
- file: image/loading_320_240.png
id: casita_initializing
resize: 640x480
type: RGB565
transparency: alpha_channel
- file: image/error-no-wifi.png
id: error_no_wifi
resize: 640x480
type: RGB565
transparency: alpha_channel
- file: image/error-no-ha.png
id: error_no_ha
resize: 640x480
type: RGB565
transparency: alpha_channel
- file: image/timer_finished_320_240.png
id: casita_timer_finished
resize: 640x480
type: RGB565
transparency: alpha_channel
font:
- file:
type: gfonts
family: Figtree
weight: 400
italic: true
id: font_request
size: 18
glyphsets: GF_Latin_Core
- file:
type: gfonts
family: Figtree
weight: 400
id: font_response
#glyphs: ${allowed_characters}
size: 20
glyphsets: GF_Latin_Core
- file:
type: gfonts
family: Figtree
weight: 400
id: font_timer
#glyphs: ${allowed_characters}
size: 36
glyphsets: GF_Latin_Core
button:
- platform: restart
name: "Jarvis Restart"
Just attach a speaker to the output of the board and connect an i2c microphone.
Cheers