From 88ecb458e1143efe2d27ed18e614381e3a058162 Mon Sep 17 00:00:00 2001 From: ducoterra Date: Sun, 15 Mar 2026 18:21:56 -0400 Subject: [PATCH] tab5 voice assist v0.1 --- active/device_esphome/tab5.yaml | 407 ++++++++++++++++++++++++++++++++ 1 file changed, 407 insertions(+) create mode 100644 active/device_esphome/tab5.yaml diff --git a/active/device_esphome/tab5.yaml b/active/device_esphome/tab5.yaml new file mode 100644 index 0000000..34ad436 --- /dev/null +++ b/active/device_esphome/tab5.yaml @@ -0,0 +1,407 @@ +esphome: + name: tab1 + friendly_name: M5Stack Tab5 1 + +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 + +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 + +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 + - 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 + + - platform: gpio + id: headphone_detect + name: "Headphone Detect" + pin: + pi4ioe5v6408: pi4ioe1 + number: 7 + +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.0; // Discharged voltage + float max_voltage = 8.23; // 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 + +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: "100%" + - platform: lvgl + widget: listen_led_widget + name: LVGL light + id: listen_led + +lvgl: + byte_order: little_endian + + on_idle: + timeout: 60s + then: + - logger.log: "LVGL is idle" + - light.turn_off: + id: backlight + transition_length: 15s + - lvgl.pause: + widgets: + - led: + id: listen_led_widget + align: CENTER + color: 0xFF0000 + brightness: 0% + height: 100px + width: 100px + - label: + align: TOP_MID + id: lbl_status + text_font: montserrat_48 + text: "IDLE" + - label: + align: BOTTOM_LEFT + id: lbl_version + text_font: montserrat_12 + text: "v0.1" + +# 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 + adc_input_mic: + name: ADC Input Mic + + - 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: + - if: + condition: lvgl.is_paused + then: + - logger.log: "LVGL resuming" + - lvgl.resume: + - light.turn_on: backlight + - light.turn_on: + id: listen_led + brightness: 100% + red: 0% + green: 100% + blue: 0% + effect: "None`" + - lvgl.label.update: + id: lbl_status + text: "LISTENING" + on_stt_vad_end: + - light.turn_on: + id: listen_led + brightness: 100% + red: 0% + green: 0% + blue: 100% + effect: "None" + - lvgl.label.update: + id: lbl_status + text: "PROCESSING" + on_tts_start: + - light.turn_on: + id: listen_led + brightness: 100% + red: 100% + green: 0% + blue: 0% + effect: "None" + - lvgl.label.update: + id: lbl_status + text: "RESPONDING" + 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.led.update: + id: listen_led_widget + color: 0x000000 + brightness: "0%" + - lvgl.label.update: + id: lbl_status + text: "IDLE" + - light.turn_off: + id: backlight + transition_length: 15s + on_client_connected: + - micro_wake_word.start: + on_client_disconnected: + - micro_wake_word.stop: