checkpoint commit
All checks were successful
Podman DDNS Image / build-and-push-ddns (push) Successful in 1m3s

This commit is contained in:
2026-05-05 06:26:40 -04:00
parent e43c534ceb
commit f2015e2c71
76 changed files with 4265 additions and 235 deletions

View File

@@ -0,0 +1,599 @@
esphome:
name: tab1
friendly_name: M5Stack Tab5 1
on_boot:
# Set the charging icon to the correct state on boot
- then:
- logger.log: "Delaying backlight initialization"
- delay: 2s
- logger.log: "End delay"
- if:
condition:
lambda: return id(charging).state;
then:
- lvgl.widget.show:
id: charging_icon_widget
else:
- lvgl.widget.hide:
id: charging_icon_widget
esp32:
board: esp32-p4-evboard
flash_size: 16MB
framework:
type: esp-idf
advanced:
enable_idf_experimental_features: true
esp32_hosted:
variant: esp32c6
active_high: true
clk_pin: GPIO12
cmd_pin: GPIO13
d0_pin: GPIO11
d1_pin: GPIO10
d2_pin: GPIO9
d3_pin: GPIO8
reset_pin: GPIO15
slot: 1
logger:
hardware_uart: USB_SERIAL_JTAG
level: DEBUG
psram:
mode: hex
speed: 200MHz
api:
# Touchscreen support
external_components:
- source: github://pr#12075
components: [st7123]
refresh: 1h
ota:
platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: true
on_connect:
- lvgl.label.update:
id: lbl_status
text: "IDLE"
- select.set:
id: dac_output
option: "LINE1"
- lvgl.label.update:
id: lbl_ip
text: !lambda return id(ip_addr).state;
- lvgl.label.update:
id: lbl_ap
text: !lambda return id(ssid).state;
on_disconnect:
- lvgl.label.update:
id: lbl_status
text: "DISCONNECTED"
text_sensor:
- platform: wifi_info
ip_address:
id: ip_addr
name: Device IP Address
address_0:
name: Device IP Address 0
address_1:
name: Device IP Address 1
address_2:
name: Device IP Address 2
address_3:
name: Device IP Address 3
address_4:
name: Device IP Address 4
ssid:
id: ssid
name: Device Connected SSID
bssid:
name: Device Connected BSSID
mac_address:
name: Device Mac Wifi Address
scan_results:
name: Device Latest Scan Results
dns_address:
name: Device DNS Address
power_save_mode:
name: Device Wifi Power Save Mode
time:
- platform: sntp
id: sntp_time
timezone: America/New_York
servers:
- 0.pool.ntp.org
- 1.pool.ntp.org
- 2.pool.ntp.org
# wireguard:
# address: !secret tab1_wg_ip
# private_key: !secret tab1_wg_pk
# peer_endpoint: !secret wg_host
# peer_public_key: !secret wg_pubkey
# # Optional keepalive (disabled by default)
# peer_persistent_keepalive: 25s
i2c:
- id: bsp_bus
sda: GPIO31
scl: GPIO32
frequency: 400kHz
pi4ioe5v6408:
- id: pi4ioe1
address: 0x43
# 0: O - wifi_antenna_int_ext
# 1: O - speaker_enable
# 2: O - external_5v_power
# 3: NC
# 4: O - lcd reset
# 5: O - touch panel reset
# 6: O - camera reset
# 7: I - headphone detect
- id: pi4ioe2
address: 0x44
# 0: O - wifi_power
# 1: NC
# 2: NC
# 3: O - usb_5v_power
# 4: O - poweroff pulse
# 5: O - quick charge enable (inverted)
# 6: I - charging status
# 7: O - charge enable
button:
- platform: restart
name: "Restart Tablet"
switch:
- platform: gpio
id: wifi_power
name: "WiFi Power"
pin:
pi4ioe5v6408: pi4ioe2
number: 0
restore_mode: ALWAYS_ON
- platform: gpio
id: usb_5v_power
name: "USB Power"
pin:
pi4ioe5v6408: pi4ioe2
number: 3
- platform: gpio
id: quick_charge
name: "Quick Charge"
pin:
pi4ioe5v6408: pi4ioe2
number: 5
inverted: true
- platform: gpio
id: charge_enable
name: "Charge Enable"
pin:
pi4ioe5v6408: pi4ioe2
number: 7
restore_mode: ALWAYS_ON
- platform: gpio
id: wifi_antenna_int_ext
pin:
pi4ioe5v6408: pi4ioe1
number: 0
- platform: gpio
id: speaker_enable
name: "Speaker Enable"
pin:
pi4ioe5v6408: pi4ioe1
number: 1
restore_mode: ALWAYS_ON
- platform: gpio
id: external_5v_power
name: "External 5V Power"
pin:
pi4ioe5v6408: pi4ioe1
number: 2
binary_sensor:
- platform: gpio
id: charging
name: "Charging Status"
pin:
pi4ioe5v6408: pi4ioe2
number: 6
mode: INPUT_PULLDOWN
on_state:
then:
- if:
condition:
lambda: return id(charging).state;
then:
- lvgl.widget.show:
id: charging_icon_widget
else:
- lvgl.widget.hide:
id: charging_icon_widget
- platform: gpio
id: headphone_detect
name: "Headphone Detect"
pin:
pi4ioe5v6408: pi4ioe1
number: 7
- platform: lvgl
widget: volume_up_widget
name: Volume Up Button
on_press:
then:
- logger.log: "Button pressed"
- media_player.volume_up:
id: tab5_media_player
- delay: 100ms
- lvgl.label.update:
id: lbl_volume
text: !lambda return to_string(int(id(tab5_media_player).volume * 100));
- light.turn_on:
id: backlight
brightness: !lambda |-
float current_value = id(backlight).current_values.get_brightness();
return current_value < 0.6 ? 0.6 : current_value + 0.2;
- platform: lvgl
widget: volume_down_widget
name: Volume Down Button
on_press:
then:
- logger.log: "Button pressed"
- media_player.volume_down:
id: tab5_media_player
- lvgl.label.update:
id: lbl_volume
text: !lambda return to_string(int(id(tab5_media_player).volume * 100));
- light.turn_on:
id: backlight
brightness: !lambda |-
float current_value = id(backlight).current_values.get_brightness();
return current_value < 0.6 ? 0.6 : current_value - 0.2;
sensor:
- platform: ina226
address: 0x41
adc_averaging: 16
max_current: 8.192A
shunt_resistance: 0.005ohm
bus_voltage:
id: battery_voltage
name: "Battery Voltage"
current:
id: battery_current
name: "Battery Current"
# Positive means discharging
# Negative means charging
# Tab5 built-in battery discharges from full (8.23 V) to shutdown threshold (6.0 V)
- platform: template
name: "Battery Percentage"
lambda: |-
float voltage = id(battery_voltage).state;
// Adjust these values based on your battery's actual min/max voltage
float min_voltage = 6.75; // Discharged voltage
float max_voltage = 8.2; // Fully charged voltage
float percentage = (voltage - min_voltage) / (max_voltage - min_voltage) * 100.0;
if (percentage > 100.0) return 100.0;
if (percentage < 0.0) return 0.0;
return percentage;
update_interval: 60s
unit_of_measurement: "%"
accuracy_decimals: 1
id: battery_percent
on_value:
then:
- lvgl.label.update:
id: lbl_battery
text:
format: "Battery: %.1f%%"
args: ["id(battery_percent).state"]
touchscreen:
- platform: st7123
i2c_id: bsp_bus
interrupt_pin: GPIO23
display: lcd
update_interval: never
reset_pin:
pi4ioe5v6408: pi4ioe1
number: 5
calibration:
x_min: 0
x_max: 720
y_min: 0
y_max: 1280
id: touch
on_touch:
- logger.log: "LVGL resuming"
- lvgl.resume:
- light.turn_on: backlight
# on_release:
# - media_player.stop:
esp_ldo:
- voltage: 2.5V
channel: 3
display:
- platform: mipi_dsi
id: lcd
dimensions:
height: 1280
width: 720
model: M5STACK-TAB5-V2
reset_pin:
pi4ioe5v6408: pi4ioe1
number: 4
output:
- platform: ledc
pin: GPIO22
id: backlight_pwm
frequency: 1000Hz
light:
- platform: monochromatic
output: backlight_pwm
name: "Display Backlight"
id: backlight
restore_mode: ALWAYS_ON
default_transition_length: 250ms
initial_state:
brightness: "50%"
image:
defaults:
type: rgb565
transparency: alpha_channel
resize: 512x512
byte_order: little_endian
images:
- file: "images/va_idle.png"
id: va_idle
- file: "images/va_listen.png"
id: va_listen
- file: "images/va_speak.png"
id: va_speak
- file: "images/charging.png"
id: charging_icon
resize: 64x64
lvgl:
byte_order: little_endian
on_idle:
timeout: 120s
then:
- logger.log: "LVGL is idle"
- light.turn_off:
id: backlight
transition_length: 15s
- lvgl.pause:
widgets:
- obj:
align: TOP_MID
width: 100%
height: 100%
layout:
type: flex
flex_flow: column
flex_align_main: START
flex_align_track: center
flex_align_cross: center
widgets:
- label:
align: TOP_MID
id: lbl_status
text_font: montserrat_48
text: "CONNECTING..."
- label:
align: TOP_MID
id: lbl_ap
text_font: montserrat_22
text: "CONNECTING..."
- label:
align: TOP_MID
id: lbl_ip
text_font: montserrat_22
text: "CONNECTING..."
- image:
id: listen_icon_widget
src: va_idle
align: CENTER
- label:
align: BOTTOM_LEFT
id: lbl_version
text_font: montserrat_12
text: "v0.6"
- label:
align: BOTTOM_RIGHT
id: lbl_battery
text_font: montserrat_28
text: Loading...
- image:
id: charging_icon_widget
src: charging_icon
align: TOP_RIGHT
- button:
id: volume_up_widget
widgets:
- label:
text: "\uF028"
text_font: montserrat_48
text_align: CENTER
align: CENTER
x: 20
y: 20
width: 100
height: 100
pad_all: 8
- button:
id: volume_down_widget
widgets:
- label:
text: "\uF027"
text_font: montserrat_48
text_align: CENTER
align: CENTER
x: 20
y: 140
width: 100
height: 100
pad_all: 8
- label:
x: 20
y: 260
id: lbl_volume
text_font: montserrat_28
text: !lambda return "%.1f",to_string(id(tab5_media_player).volume);
# The DAC Output select needs to be manually (or with an automation) changed to `LINE1` for the onboard speaker
select:
- platform: es8388
dac_output:
name: DAC Output
id: dac_output
adc_input_mic:
name: ADC Input Mic
id: adc_input
- platform: template
id: wifi_antenna_select
name: "WiFi Antenna"
options:
- "Internal"
- "External"
optimistic: true
on_value:
- if:
condition:
lambda: return i == 0;
then:
- switch.turn_off: wifi_antenna_int_ext
else:
- switch.turn_on: wifi_antenna_int_ext
i2s_audio:
- id: mic_bus
i2s_lrclk_pin: GPIO29
i2s_bclk_pin: GPIO27
i2s_mclk_pin: GPIO30
audio_adc:
- platform: es7210
id: es7210_adc
bits_per_sample: 16bit
sample_rate: 16000
microphone:
- platform: i2s_audio
id: tab5_microphone
i2s_din_pin: GPIO28
sample_rate: 16000
bits_per_sample: 16bit
adc_type: external
audio_dac:
- platform: es8388
id: es8388_dac
speaker:
- platform: i2s_audio
id: tab5_speaker
i2s_dout_pin: GPIO26
audio_dac: es8388_dac
dac_type: external
channel: mono
buffer_duration: 100ms
bits_per_sample: 16bit
sample_rate: 48000
media_player:
- platform: speaker
name: None
id: tab5_media_player
announcement_pipeline:
speaker: tab5_speaker
format: WAV
micro_wake_word:
id: mww
models:
- okay_nabu
- hey_mycroft
- hey_jarvis
on_wake_word_detected:
- voice_assistant.start:
wake_word: !lambda return wake_word;
voice_assistant:
id: va
microphone: tab5_microphone
media_player: tab5_media_player
micro_wake_word: mww
on_listening:
- logger.log: "LVGL resuming"
- lvgl.resume:
- light.turn_on: backlight
- lvgl.image.update:
id: listen_icon_widget
src: va_listen
- lvgl.label.update:
id: lbl_status
text: "LISTENING"
on_stt_vad_end:
- lvgl.label.update:
id: lbl_status
text: "PROCESSING"
- lvgl.image.update:
id: listen_icon_widget
src: va_idle
on_tts_start:
- lvgl.label.update:
id: lbl_status
text: "RESPONDING"
- lvgl.image.update:
id: listen_icon_widget
src: va_speak
on_end:
# Wait a short amount of time to see if an announcement starts
- wait_until:
condition:
- media_player.is_announcing:
timeout: 0.5s
# Announcement is finished and the I2S bus is free
- wait_until:
- and:
- not:
media_player.is_announcing:
- not:
speaker.is_playing:
- micro_wake_word.start:
- lvgl.label.update:
id: lbl_status
text: "IDLE"
- lvgl.image.update:
id: listen_icon_widget
src: va_idle
- light.turn_off:
id: backlight
transition_length: 15s
on_client_connected:
- micro_wake_word.start:
on_client_disconnected:
- micro_wake_word.stop: