GUITION 4" 480x480 ESP32-S3-4848S040 Smart Display with LVGL

The code now is (kaku) working (or do I something wrong?):

# Update button and relay state from Home Assistant
button_5_sensor: !include { file: modules/sensors/basic_switch_or_light_button_state.yaml, vars: { id: 5 } }

widgets: # Include all the buttons
        - button: !include { file: modules/lvgl/buttons/basic_switch_kuka_button.yaml, vars: { id: 5, height: $button_height_single }

I have add /config/modules/lvgl/buttons/basic_switch_kuka_button.yaml (only change switch to light)

# Basic kaku switch button - define its setting in substitutions
            height: ${height}
            checkable: true
            id: lv_button_${id}
            widgets:
              - label:
                  text_font: $icon_font
                  align: top_left
                  id: lv_button_${id}_icon
                  text: $button_${id}_icon
              - label:
                  align: bottom_left
                  id: lv_button_${id}_label
                  text: $button_${id}_name
            on_click:
                - homeassistant.service:
                    service: light.toggle
                    data:
                      entity_id: $button_${id}_device

From my pages.jsonl:

{"id":24,"obj":"label","x":90,"y":380,"h":90,"w":300,"text":"TI:ME","template":"%H:%M","align":"center","text_font":90,"bg_color":"#2C3E50","text_color":"#FFFFFF"}

The relevant part is "template":"%H:%N" which overwrites “text” once a valid time is grabbed from an NTP server.

Also see the first section of: Example Configurations - openHASP

1 Like

5 years ago I wrote a piece of html (php) and javascript code for my Denon amplifier to control it from an internet page . This page also contains the buttons for controlling the house.


^screenshot mobile phone zone1/zone2^

I have been persuaded to work with Home Assistant, which is why I am now working on integrating the control of the Denon, which should also work on this 7" display.

For the volume control I have created rest_command in HA and for the display a modified basic_pulse_repeat_button.yaml. This works well :slight_smile:

I am now faced with the challenge that I want to read the status from the Denon (XML) for the volume number in the buttons, the scroll on the display and that I have a mute button that shows the actual status.
Does anyone have a few tips for that, to read the XML and process this in the buttons

http://<IP-ADDRESS>:8080/goform/formZone2_Zone2XmlStatusLite.xml

<?xml version="1.0" encoding="utf-8" ?>
<item>
<Power><value>ON</value></Power>
<MasterVolume><value>-48</value></MasterVolume>
<Mute><value>off</value></Mute>
</item>

Working pulse repeat button

 button_8_name: "Volume"
 button_8_id: Vol_down
 button_8_icon: $volume_down
 button_8_device: rest_command.vol_down

basic_pulse_repeat_button.yaml

# Basic pulse repeat button - define its setting in substitutions
            height: ${height}
            checkable: False
            pressed:
              bg_color: 0xFFFFFF
            id: lv_button_${id}
            widgets:
              - label:
                  text_font: $icon_font
                  align: top_left
                  id: lv_button_${id}_icon
                  text: $button_${id}_icon
              - label:
                  align: bottom_left
                  id: lv_button_${id}_label
                  text: $button_${id}_name
            on_long_press_repeat:
                - homeassistant.service:
                    service: $button_${id}_device
                    data: {}
            on_click:
                - homeassistant.service:
                    service: $button_${id}_device
                    data: {}

2 Likes

Hi Dirk, can’t you use any of these: Integrations → Denon

No, I had tried too. No direct volume control, but (apparently) a volume adjustment to HA is pushed. This is what you want anyway, where I solve it with a sensor that picks up the XML from the AVR.

<edit>
I have checked the communication between HA and the Denon.
HA makes a telnet connections to the Denon.

Every time I send and http-get to the Denon, Denon shows the action on the Telnet-feed that will be read by HA.

http-get that I send:

GET /goform/formiPhoneAppDirect.xml?Z2UP HTTP/1.1
Host: <IP-ADDRESS>:8080

telnet-feed:

Z230
Z231
Z232
Z233
Z234
Z235
Z236

</edit>


^ screenshot of the Media control Cards^


^if I press on the dots in the right corner^

According to the list of supported receivers, yours should work.

What do you mean with should work? I want the buttons on the ‘frontpage’ to change the volume, mute, etc. Do I miss an option or setting?\

But this is a bit off topic

Thanks, that’s nice!

Then I still can’t get toggle yet with the power and mute function (vol up/down works fine)

Turn off

show_name: true
show_icon: true
type: button
tap_action:
  action: perform-action
  perform_action: media_player.turn_off
  target:
      entity_id: media_player.denon_avc_x3700h_2
  data: {}
entity: media_player.denon_avc_x3700h_2
icon_height: 20px
icon: mdi:power

Volume + (up)

show_name: false
show_icon: true
type: button
tap_action:
  action: perform-action
  perform_action: media_player.volume_up
  target:
    entity_id: media_player.denon_avc_x3700h_2
  data: {}
entity: media_player.denon_avc_x3700h_2
icon_height: 20px
icon: mdi:volume-plus
show_state: false

Mute

show_name: true
show_icon: true
type: button
tap_action:
  action: perform-action
  perform_action: media_player.volume_mute
  target:
    entity_id: media_player.denon_avc_x3700h_2
  data:
    is_volume_muted: false
entity: media_player.denon_avc_x3700h_2
icon: mdi:volume-mute
icon_height: 20px

This weather / tide clock has the time in the upper right hand corner.

My esphome-modular-lvgl-buttons libary already calls the script time_update. You just need to add the code that updates your label. You can see my code that updates the time label. It looks like this.

      - lvgl.label.update:
          id: time_label
          text: !lambda 'return id(system_time).now().strftime("%l:%M %P");' # The format %I:%M %p will display the time in a 12-hour format with "am" or "pm" included

And this is what the time label itself looks like.

          # Time display - upper right          
          - label:
                id: time_label
                width: SIZE_CONTENT
                height: SIZE_CONTENT
                pad_all: 3
                bg_opa: cover
                bg_color: burnt_sienna
                text_color: white
                align: TOP_RIGHT
                text_align: right
                text_font: roboto24
                text: "00:00 am"

The esphome-modular-lvgl-buttons library has an “empty button” just modify that with a label for your time.

How can I use other icons like volume up and down?
I thought I am adding these substitutions and then refer to it from the button, but that gives an untreated icon.

volume_plus: "\U000f075d"
volume_minus: "\U000f075e"
volume_mute: "\U000f075f"

source: Convert unicode

Yeah that code looks right. I We are using the [Material Design Icons]Material Design Icons and those look like the right character icons.

Did you add your icons to the font list in the correct size you are trying to use?

Simplified the use of the pages, made the pages more versatile. Esphome-ESP32-S3-4848S040-LVGL/Packages.yaml at 545f5a9a22b7b8d4d4a6b4dd5051ba2567d0fb01 · ananyevgv/Esphome-ESP32-S3-4848S040-LVGL · GitHub

has anyone done sonoff.send_command?
action:sonoff.send_command
data:
device: ‘1000fd870d’
switch: ‘[{outlet: 0, switch: on}]’
does not work.
switch: ‘[{outlet: 0, switch: ‘off’}]’
it doesn’t compile.

I had fun with deepseek see if it’s good

import requests
import xml.etree.ElementTree as ET
import tkinter as tk

def fetch_xml_data(ip_address):
    url = f"http://{ip_address}:8080/goform/formZone2_Zone2XmlStatusLite.xml"
    try:
        response = requests.get(url)
        response.raise_for_status()
        return response.content
    except requests.exceptions.RequestException as e:
        print(f"Erreur de connexion: {e}")
        return None

def parse_xml(xml_data):
    zones = []
    root = ET.fromstring(xml_data)
    
    for zone in root.findall('zone'):
        zone_info = {
            'id': zone.get('id'),
            'name': zone.get('name'),
            'state': zone.get('val') == '1',
            'volume': zone.get('vol'),
            'bass': zone.get('bass'),
            'treble': zone.get('treble')
        }
        zones.append(zone_info)
    return zones

def update_zone_state(ip_address, zone_id, state):
    url = f"http://{ip_address}:8080/goform/formiPhoneAppDirect.xml"
    params = {
        'Z' + zone_id: '1' if state else '0'
    }
    try:
        response = requests.post(url, params=params)
        response.raise_for_status()
    except requests.exceptions.RequestException as e:
        print(f"Erreur de mise Ă  jour: {e}")

class ZoneControlApp:
    def __init__(self, master, ip_address):
        self.master = master
        self.ip_address = ip_address
        self.zones = []
        
        self.create_widgets()
        self.refresh_data()
        
    def create_widgets(self):
        self.frame = tk.Frame(self.master)
        self.frame.pack(padx=10, pady=10)
        
        self.buttons = []
        for i in range(5):  # Création de 5 boutons
            btn = tk.Button(self.frame, 
                          width=15, 
                          height=3,
                          command=lambda i=i: self.toggle_zone(i))
            btn.grid(row=i//3, column=i%3, padx=5, pady=5)
            self.buttons.append(btn)
            
        self.refresh_btn = tk.Button(self.master, 
                                    text="Actualiser",
                                    command=self.refresh_data)
        self.refresh_btn.pack(pady=5)
        
    def refresh_data(self):
        xml_data = fetch_xml_data(self.ip_address)
        if xml_data:
            self.zones = parse_xml(xml_data)
            self.update_buttons()
            
    def update_buttons(self):
        for i, zone in enumerate(self.zones):
            if i < len(self.buttons):
                state_text = "ON" if zone['state'] else "OFF"
                color = "green" if zone['state'] else "red"
                self.buttons[i].config(
                    text=f"Zone {zone['id']}\n{state_text}",
                    bg=color
                )
                
    def toggle_zone(self, zone_index):
        if zone_index < len(self.zones):
            zone = self.zones[zone_index]
            new_state = not zone['state']
            update_zone_state(self.ip_address, zone['id'], new_state)
            self.refresh_data()

if __name__ == "__main__":
    IP_ADDRESS = "<ADRESSE-IP>"  # Remplacer par l'IP réelle
    
    root = tk.Tk()
    root.title("ContrĂŽle de Zones Audio")
    app = ZoneControlApp(root, IP_ADDRESS)
    root.mainloop()

Hello, would you happen to have step-by-step instructions on how to do this?

I would like to connect this device to my Raspberry Pi 3B+ or a WROOM ESP32, preferably wirelessly, but a wired connection is also an option. My goal is to turn it into a control center:

Display the weather on the screen.
Manage my MP3 library (files stored on the Raspberry Pi’s SD card).
Access my Spotify account to control playback.
Wirelessly stream music to my Denon CEOL N9 hi-fi system.

Would something like this be technically possible? For now, at home, I only have two connected LED lamps


Hi, this is an English only forum and topics in another language will be closed by a mod.

How to help us help you - or How to ask a good question →
language

Alternative: Getting help in languages other than English

I’ve flashed the Modular Buttons to my Guition device. I’ve tweaked the code so I can access all 3 of my relays and also some extra buttons to control some lights that are in Home Assistant.

I have found that once you have more buttons than will fit on the screen it will then allow you to swipe from right to left to see the extra buttons. this works but now we’re all used to snappy iphones and the latest android devices responding instantly, when you use this it feels really sluggish (which is fair given the relative power of this devive) but is it possible to make it that when you swipe it doesn’t scroll but just redraws the screen on the next “page”, just like how it responds when you have the menu bar and tap the next page, but without needing the menu bar and its buttons. Hope that makes sense.

Also, is it possible to make a kind of screensaver page that shows my energy use as a meter? I cant just figure out even how to add an energy meter to begin with let alone making it so it appears after a timeout period of inactivity.

I’m after when its not in use it displays my energy use but as soon as you tap it then the normal “home screen” with the buttons etc appears. It would be awesome if the energy use could also show my battery and solar in there too like the energy meter thats baked into home assistant can. I do of course have all the relevant sensor entities present in home assistant to provide the data.

These little Guition devices are excellent, I wonder how long they’ll last!! Here in the UK they are the same size as standard wall switches so look amazing when replacing the non smart regular switches.

This is the scroll feature and as you mentioned does not work well. just make a new page if you want more buttons. I would group them with a button on the fist page the has the name of the group and open the page with the buttons for that group.

Yeah that should be fairly easy. I have some examples with clocks that are similar to an energy meter. I also have an example the shown some info from my Enphase solar system.

Make a list of info you want from your solar setup.

I have been working on a solar/battery display page. Is this what you are looking for? What other sensors/meters should I add?