esphome: name: music-cyd friendly_name: Music CYD esp32: board: esp32dev framework: type: esp-idf # Enable logging logger: # Enable Home Assistant API api: homeassistant_services: true encryption: key: "replace_with_your_key" ota: - platform: esphome password: !secret ota_password wifi: ssid: !secret wifi_ssid password: !secret wifi_password # Enable fallback hotspot (captive portal) in case wifi connection fails ap: ssid: "Music-Cyd Fallback Hotspot" password: "VxBhBCmF4xFO" captive_portal: substitutions: player: media_player.family_room vup_str: "\U000F075D" vdn_str: "\U000F075E" # Defines the colors we want to use later for the different buttons. # Per-button customizable colors color: - id: room_bg_color hex: "000000" - id: default_button_bg_color hex: "000000" - id: default_button_pressed_bg_color hex: "D3D3D3" - id: song_color hex: FF7F00 # Orange - id: artist_color hex: 00FFFF # Aqua - id: album_color hex: 00FFFF # Aqua - id: color_btn hex: "FFFFFF" # White #-------------------------------------------------------------------------------- # # Fonts. I listen to a lot of Japanese music, so I've pulled the characters # from the song/album titles and added them here. If you don't need this, you # can probably use a simpler font like Roboto, and not have to add all the # extras. # #-------------------------------------------------------------------------------- font: - file: "fonts/NotoSansJP-Medium.ttf" id: font_song size: 40 bpp: 4 extras: - file: "fonts/NotoSansJP-Medium.ttf" glyphs: ['二', '何', '侍', '優', '加', '天', '子', '帰', '徒', '智', '枚', '死', '灯', '炎', '特', '白', '目', '罪', '花', '調', '賀', '赤', '跡', '軌', '雷', '霆', '風', '香', '鬼'] - file: "gfonts://Roboto" id: font_artist bpp: 4 size: 32 - file: "fonts/NotoSansJP-Medium.ttf" id: font_album bpp: 4 size: 28 extras: - file: "fonts/NotoSansJP-Medium.ttf" glyphs: ['二', '何', '侍', '優', '加', '天', '子', '帰', '徒', '智', '枚', '死', '灯', '炎', '特', '白', '目', '罪', '花', '調', '賀', '赤', '跡', '軌', '雷', '霆', '風', '香', '鬼'] - file: "fonts/materialdesignicons-webfont.ttf" # Defining Material Design Icons as a font. This id: font_mdi # will allow us to use them as button icons. size: 50 # You can get these glyphs from the https://pictogrammers.com/library/mdi/ glyphs: # where you choose the icon, and then "copy glyph". - ${vup_str} # Volume Up - ${vdn_str} # Volume Down #-------------------------------------------------------------------------------- # # I2C Controller to connect o the NFC sensor # #-------------------------------------------------------------------------------- i2c: timeout: 10ms scan: True scl: GPIO25 sda: GPIO32 #-------------------------------------------------------------------------------- # # NFC Sensor. Determines the NFC code and sets the rfid_tag sensor that # home assistant can monitor. When the card is removed, set the sensor to # None, so that home assistant can determine it was removed. # #-------------------------------------------------------------------------------- pn532_i2c: update_interval: 1s on_tag: then: - light.turn_on: backlight - text_sensor.template.publish: id: rfid_tag state: !lambda 'return x;' - homeassistant.tag_scanned: !lambda | if (!tag.has_ndef_message()) { return x; } auto message = tag.get_ndef_message(); auto records = message->get_records(); for (auto &record : records) { std::string payload = record->get_payload(); size_t pos = payload.find("https://www.home-assistant.io/tag/"); if (pos != std::string::npos) { return payload.substr(pos + 34); } } return x; on_tag_removed: then: - light.turn_off: backlight - text_sensor.template.publish: id: rfid_tag state: "None" #-------------------------------------------------------------------------------- # # Lights # #-------------------------------------------------------------------------------- light: # LCD backlight - platform: monochromatic output: backlight_pwm name: "Display Backlight" id: backlight restore_mode: ALWAYS_ON # onboard rgb led - platform: rgb name: "Back LED" id: front_led restore_mode: ALWAYS_OFF red: led_red green: led_green blue: led_blue # ============================================================ # Touchscreen Display related setup # ============================================================ # Set pins to control the backlight and RGB LED. Still haven't figured this out yet. output: - platform: ledc pin: GPIO27 id: backlight_pwm - platform: ledc pin: GPIO22 id: led_red inverted: true - platform: ledc pin: GPIO16 id: led_green inverted: true - platform: ledc pin: GPIO17 id: led_blue inverted: true #-------------------------------------------------------------------------------- # # SPI bus for TFT display and touch controller # #-------------------------------------------------------------------------------- spi: - id: spi_tft clk_pin: GPIO14 mosi_pin: GPIO13 miso_pin: GPIO12 time: - platform: sntp on_time: - hours: 2,3,4,5 minutes: 5 seconds: 0 then: - switch.turn_on: switch_antiburn - hours: 2,3,4,5 minutes: 35 seconds: 0 then: - switch.turn_off: switch_antiburn #------------------------------------------------------------------------------- # # Found this code to reduce burn-in # #------------------------------------------------------------------------------- switch: - platform: template name: Antiburn id: switch_antiburn icon: mdi:television-shimmer optimistic: true entity_category: "config" turn_on_action: - logger.log: "Starting Antiburn" - if: condition: lvgl.is_paused then: - lvgl.resume: - lvgl.widget.redraw: - lvgl.pause: show_snow: true turn_off_action: - logger.log: "Stopping Antiburn" - if: condition: lvgl.is_paused then: - lvgl.resume: - lvgl.widget.redraw: #-------------------------------------------------------------------------------- # # Defining the touchscreen for later use # #-------------------------------------------------------------------------------- touchscreen: - platform: xpt2046 id: my_touch display: my_display spi_id: spi_tft cs_pin: GPIO33 interrupt_pin: GPIO36 update_interval: 50ms transform: swap_xy: true mirror_x: false mirror_y: false calibration: x_min: 200 x_max: 3900 y_min: 200 y_max: 3900 on_release: then: - if: condition: lvgl.is_paused then: - lvgl.resume: - lvgl.widget.redraw: #-------------------------------------------------------------------------------- # # Home Assistant sensors for the buttons # #-------------------------------------------------------------------------------- binary_sensor: - platform: template name: "Volume Up" id: volume_up_pressed - platform: template name: "Volume Down" id: volume_down_pressed #-------------------------------------------------------------------------------- # # Home Assistant sensor for the RFID tag for this module # # Song information is pulled from Home Assistant media player # #-------------------------------------------------------------------------------- text_sensor: # Exported to Home Assistant - platform: template name: "RFID Tag" id: rfid_tag # Imported from Home Assistant - platform: homeassistant id: current_song entity_id: ${player} attribute: media_title on_value: - lvgl.label.update: id: song_name text: !lambda |- return id(current_song).state; - platform: homeassistant id: current_artist entity_id: ${player} attribute: media_artist on_value: - lvgl.label.update: id: artist_name text: !lambda |- return id(current_artist).state; - platform: homeassistant id: current_album entity_id: ${player} attribute: media_album_name on_value: - lvgl.label.update: id: album_name text: !lambda |- return id(current_album).state; #-------------------------------------------------------------------------------- # # Define the display # #-------------------------------------------------------------------------------- display: - platform: ili9xxx id: my_display model: ST7796 spi_id: spi_tft dc_pin: GPIO2 cs_pin: GPIO15 dimensions: width: 480 height: 320 data_rate: 80MHz color_order: BGR invert_colors: false update_interval: 5s auto_clear_enabled: false show_test_card: false transform: swap_xy: true mirror_y: true mirror_x: true #-------------------------------------------------------------------------------- # # Import the media player's volume level and use it to set the slider # #-------------------------------------------------------------------------------- sensor: - platform: homeassistant id: media_player_volume entity_id: ${player} attribute: volume_level on_value: - lvgl.bar.update: id: slider_media_player value: !lambda return (x * 100); #-------------------------------------------------------------------------------- # # Graphics are controlled via LVGL # #-------------------------------------------------------------------------------- lvgl: buffer_size: 25% theme: button: # This base is overridden by each button's bg_color bg_color: 0x000000 bg_opa: COVER border_color: 0x000000 border_width: 1 text_color: 0xFFFFFF # overridden per label using text_color: btn_x_color pressed: # Light grey for pressed state (used uniformly) bg_color: 0xC0C0C0 bg_grad_color: 0xC0C0C0 bg_opa: COVER checked: bg_color: 0x000000 bg_grad_color: 0x000000 bg_opa: COVER text_color: 0x800080 # purple icon when "checked"... entity is on pages: - id: main_page pad_all: 0 widgets: - obj: width: 480 height: 320 bg_color: room_bg_color layout: type: grid grid_columns: [fr(1), fr(1), fr(1), fr(1), fr(1)] grid_rows: [fr(1), fr(1), fr(1), fr(1)] pad_all: 5px outline_pad: 5px widgets: - button: id: btn_1 grid_cell_column_pos: 4 grid_cell_row_pos: 3 grid_cell_x_align: STRETCH grid_cell_y_align: STRETCH bg_color: default_button_bg_color pressed: bg_color: default_button_pressed_bg_color widgets: - label: id: lbl_btn_1 text: ${vup_str} text_font: font_mdi text_color: color_btn align: center on_click: then: - binary_sensor.template.publish: id: volume_up_pressed state: ON - delay: 500ms - binary_sensor.template.publish: id: volume_up_pressed state: OFF - button: id: btn_2 grid_cell_column_pos: 0 grid_cell_row_pos: 3 grid_cell_x_align: STRETCH grid_cell_y_align: STRETCH bg_color: default_button_bg_color pressed: bg_color: default_button_pressed_bg_color widgets: - label: id: lbl_btn_2 text: ${vdn_str} text_font: font_mdi text_color: color_btn align: center on_click: then: - binary_sensor.template.publish: id: volume_down_pressed state: ON - delay: 500ms - binary_sensor.template.publish: id: volume_down_pressed state: OFF - label: id: song_name grid_cell_column_pos: 0 grid_cell_row_pos: 0 grid_cell_column_span: 5 text_align: CENTER text: "" text_color: song_color text_font: font_song grid_cell_x_align: STRETCH grid_cell_y_align: STRETCH - label: id: artist_name grid_cell_column_pos: 1 grid_cell_row_pos: 1 grid_cell_column_span: 3 text_align: CENTER text: "" text_color: artist_color text_font: font_artist grid_cell_x_align: STRETCH grid_cell_y_align: STRETCH - label: id: album_name grid_cell_column_pos: 0 grid_cell_row_pos: 2 grid_cell_column_span: 5 text_align: CENTER text: "" text_color: album_color text_font: font_album grid_cell_x_align: STRETCH grid_cell_y_align: STRETCH - bar: id: slider_media_player grid_cell_column_pos: 1 grid_cell_row_pos: 3 grid_cell_column_span: 3 grid_cell_x_align: STRETCH grid_cell_y_align: CENTER