Planning and setup - ESP32-S3 - 4848S040 - 480*480 IPS touchscreen

THIS IS A OPEN SOURCE PROJECT THERE ARE NO FEES

Here is what I did:

Install Firmware

  1. Connect display with your computer
  2. Flash the Firmware: Use Chrome Browser while you on the Nightly Build-Site Select “Guition ESP32-S3-4848S040” and Install
  3. Setting Up Wifi: Follow Instructions on the screen

Install HomeAssistant Components

  1. HACS: Install HACS if you haven’t already
  2. MQTT: Install and setup Home Assistant Add-on: Mosquitto broker if you haven’t already (OpenHasp and the Display communicate via MQTT)
  3. openHASP Custom Component: Install The OpenHASP Component from within HACS

Set up HomeAssistant

  1. Make sure your Display is running and reachable (Default setup shows with text “plate” on the top left corner of the screen and a popup with the actual IP-Adress).
  2. Go to shown IP-Adress with browser goto: http://your_ip/config/mqtt and fill in mqtt credentials from step 2 (see above)
  3. Got to shown IP-Adress with browser goto: http://your_ip/edit delete the pre-defined pages.jsonl file (Optional, otherwise Display loads this during startup)
  4. Go to shown IP-Adress with browser goto: http://your_ip/config/gpio and add:
    GPIO Output
    PIN: 40 (May be different on other Displays)
    TYPE: Power Relay
    Groupe: None
    Value: Normal
    I had issues with entity naming when I skipped this step
  5. SetUp your display within Homeassistant detailed information here and follow the example we’ll edit the files later on. If everything works as aspected the display will be auto-discovered by OpenHASP-Component
  6. Add a HA-Template sensor in configuration.yaml and edit to your needs (May use http://gridcalculator.dk/ to calculate col and gutter values)
template:
  - binary_sensor:
    - name: Display settings
      unique_id: 1b3a3dae-fd0c-4f47-9c8b-5b680478a977 # https://www.uuidgenerator.net/
      state: "{{ now() }}"
      attributes:
        display_w: "480"
        display_h: "480"
        grid_cols: "12" # increase for more resolution of object
        grid_rows: "12" # increase for more resolution of object
        grid_gutter: "8" # This looked nice for me
        grid_margin: "4" # This looked nice for me
        bg_color: "#000000"
        primary_color: "#4193d5"
        secondary_color: "#ee9f52"
        accent_color: "#A175C4"
        success_color: "#6cbe58"
        warning_color: "#d67430"
        error_color: "#e25628"
        radius: "4"

  1. If you’re done you should have a working display which is integrated in Homeassistant and comunicates via MQTT as well as a New Template Sensor with the given attributes
  2. Further reading if everything worked as aspected

Customizing

OpenHASP is highly customizable. Every Object can be set pixel perfect. This means you have to define every Width/Height x-and y-position.
To get rid of this I wrote I simple Jinja-Template. So I set Up dimensions with a grid system instead of pixel values. EXAMPLE:

Get Postion and size like this

{% import 'openhasp.jinja' as grid %} 
w = {{grid.w(1)}}
h = {{grid.h(1)}}
x = {{grid.x(1)}}
y = {{grid.y(1)}}

This Example generates the size (1x1) and coordinates ( 1st from left, 1ist from top) for the given display settings

Get colors like this

color = {% from 'openhasp.jinja' import color %}{{color('primary')}}
light_color = {% from 'openhasp.jinja' import color %}{{color('primary_light')}}
dark_color = {% from 'openhasp.jinja' import color %}{{color('primary_dark')}}

This Example generates Color Values. So if you want to change colors, just change the attribute of the Display settings sensor instead of changing the openhasp config

Try yourself

  1. In the folder “custom_templates” add a new file: openhasp.jinja
{%- macro grid() -%}
    {%- set settingsSensor = 'binary_sensor.display_settings' -%}
    {%- set dw = (state_attr(settingsSensor, 'display_w') | default(240)) | int -%}
    {%- set dh = (state_attr(settingsSensor, 'display_h') | default(240)) | int -%}
    {%- set cols = (state_attr(settingsSensor, 'grid_cols') | default(6)) | int -%}
    {%- set rows = (state_attr(settingsSensor, 'grid_rows') | default(6)) | int -%}
    {%- set margin = (state_attr(settingsSensor, 'grid_margin') | default(10)) | int -%}
    {%- set gutter = (state_attr(settingsSensor, 'grid_gutter') | default(10)) | int -%}
    {%- set radius = (state_attr(settingsSensor, 'radius') | default(5)) | int -%}
    {{- 
        {
            'w': (dw - (2 * margin) - ((cols-1) * gutter)) / cols, 
            'h': (dh - (2 * margin) - ((rows-1) * gutter)) / rows,
            'cols' : cols,
            'rows' : rows,
            'margin' : margin,
            'gutter' : gutter,
            'display_width' : dw,
            'display_height' : dh,
            'radius': radius
        } | to_json 
    -}}
{%- endmacro -%}

{%- macro w(w) -%}
    {%- set gutter = (grid() | from_json).gutter | default(10) | int -%}
    {%- set errors = namespace(w=[]) %}
    {%- if w > (grid() | from_json).cols or w <= -1 -%}
        {% set errors.w = 'cols must be between 1 and ' + (grid() | from_json).cols | string %}
    {%- endif -%}
    {{- errors.w if errors.w | count > 0 else (w * (grid() | from_json).w | int) + ((w-1) * gutter | int) -}}    
{%- endmacro -%}

{%- macro h(h) -%}
    {%- set gutter = (grid() | from_json).gutter | default(10) | int -%}
    {%- set errors = namespace(h=[]) %}
    {%- if h > (grid() | from_json).rows or h <= -1 -%}
        {% set errors.h = 'rows must be beetween 1 and ' + (grid() | from_json).rows | string %}
    {%- endif -%}
    {{- errors.h if errors.h | count > 0 else (h * (grid() | from_json).h | int) + ((h-1) * gutter | int) -}}    
{%- endmacro -%}

{%- macro x(x) -%}
    {%- set x = x-1 | default(1) -%}
    {%- set margin = (grid() | from_json).margin | default(10) | int -%}
    {%- set gutter = (grid() | from_json).gutter | default(10) | int -%}
    {%- set width = w(x) | int -%}
    {{- (margin if x == 0 else (margin + width + gutter)) if width is number else width -}}
{%- endmacro -%}

{%- macro y(y) -%}
    {%- set y = y-1 | default(1) -%}
    {%- set margin = (grid() | from_json).margin | default(10) | int -%}
    {%- set gutter = (grid() | from_json).gutter | default(10) | int -%}
    {%- set height = h(y) | int -%}
    {{- (margin if y == 0 else (margin + height + gutter)) if height is number else height -}}
{%- endmacro -%}

{%- macro AdjustColor(hex, brightness) -%}
    {%- set brightness = brightness|default(0.1) -%}
    {%- set hex = hex|replace('#', '')|replace('/[^0-9a-f]/gi', '') -%}
    {%- if hex|length < 6 -%}
        {%- set hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2] -%}
    {%- endif -%}
    {%- set color = namespace(rgb='') -%}
    {%- set color.rgb = '#' -%}
    {%- for i in range(0, 6, 2) -%}
        {%- set c = hex[i:i+2]|int(base=16) -%}
        {%- set c = (c + (c * brightness))|round|int -%} 
        {%- set c = 0 if c < 0 else ( 255 if c > 255 else c) -%}
        {%- set c = "%02x"|format(c) -%}
        {%- set color.rgb = color.rgb + c -%} 
    {%- endfor -%}
    {{- color.rgb -}}
{%- endmacro -%}

{%- macro color(name) -%}
    {%- set s = name.split("_") -%}
    {%- set base = state_attr('binary_sensor.display_settings',  s[0]+'_color') | default('#000000') -%}
    {%- if s | count > 1 and s[1] == 'light' -%}
        {{ AdjustColor(base, 0.2) }}
    {%- elif s | count > 1 and s[1] == 'dark' -%}
        {{ AdjustColor(base, -0.2) }}
    {%-else-%}
        {{ base  -}}
    {%- endif %}
{%- endmacro -%}
  1. In your plate.json file:
[
    "SEITE 0 - SETTINGS",
    {
        "page": 1,
        "id": 0,
        "prev": 4
    },
    "SEITE 0 - PREVIOUS -BUTTON",
    {
        "page": 0,
        "id": 1,
        "obj": "btn",
        "outline_opa": 0,
        "border_opa": 0,
        "text_font": 32,
        "toggle": false,
        "action": "prev"
    },
    "SEITE 0 - HOME - BUTTON",
    {
        "page": 0,
        "id": 2,
        "obj": "btn",
        "outline_opa": 0,
        "border_opa": 0,
        "text_font": 32,
        "toggle": false,
        "action": {
            "down": "back",
            "hold": "restart"
        }
    },
    "SEITE 0 - NEXT - BUTTON",
    {
        "page": 0,
        "id": 3,
        "obj": "btn",
        "text": "\uE054",
        "outline_opa": 0,
        "border_opa": 0,
        "text_font": 32,
        "action": "next",
        "toggle": false
    },
    "SEITE 1 - CONTAINER",
    {
        "page": 1,
        "id": 2,
        "obj": "obj",
        "border_opa": 0,
        "bg_opa": 0,
        "click": 0
    }
]
  1. In your homeassistant configuration.yaml add:
openhasp:
  display02: # depends on you given device Name!!!
    objects:
      # SEITE 0
      - obj: "p0b0" # SETTINGS
        properties:
          "jsonl": >
            {% from 'openhasp.jinja' import color %}
            {{
              {
                'bg_color' : color('bg')
              } |to_json |string
            }}
      - obj: "p0b1" # PREVIOUS - BUTTON"
        properties:
          "jsonl": >
            {% from 'openhasp.jinja' import grid,w,h,x,y,color %}
            {{
                {
                    'w': w(4)|int,
                    'h': h(2)|int,
                    'x': x(1)|int,
                    'y': y(11)|int,
                    'radius': (grid() | from_json).radius |int,
                    'bg_color': color('primary'),
                    'bg_color02': color('primary_light'),
                    'text': "\uE04D"
                  } |to_json |string
            }}
      - obj: "p0b2" # HOME - BUTTON
        properties:
          "jsonl": >
            {% from 'openhasp.jinja' import grid,w,h,x,y,color %}
            {{
                {
                    'w': w(4)|int,
                    'h': h(2)|int,
                    'x': x(5)|int,
                    'y': y(11)|int,
                    'radius': (grid() | from_json).radius |int,
                    'bg_color': color('primary'),
                    'bg_color02': color('primary_light'),
                    'text': "\uE6A1"
                  } |to_json |string
            }}
      - obj: "p0b3" # NEXT - BUTTON
        properties:
          "jsonl": >
            {% from 'openhasp.jinja' import grid,w,h,x,y,color %}
            {{
                {
                    'w': w(4)|int,
                    'h': h(2)|int,
                    'x': x(9)|int,
                    'y': y(11)|int,
                    'radius': (grid() | from_json).radius |int,
                    'bg_color': color('primary'),
                    'bg_color02': color('primary_light'),
                    'text': "\uE054"
                  } |to_json |string
            }}    
      # SEITE 1
      - obj: "p1b0" # SETTINGS
        properties:
          "jsonl": >
            {% from 'openhasp.jinja' import color %}
            {{
                {
                  'bg_color': color('bg')
                } |to_json |string
            }}
      - obj: "p1b2" # CONTAINER
        properties:
          "jsonl": >
            {% from 'openhasp.jinja' import grid,h %}
            {{
                {
                    'w': (grid() | from_json).display_width,
                    'h': h(10)|int,
                    'x': 0|int,
                    'y': 0|int
                } |to_json |string
            }}
  1. Restart The Display and/or Open your Home Assistant instance and show your service developer tools with a specific service selected. reload_config_entry for your device to see your changes

  2. From now on you’re on your own. Feel free to share yours

Here is my display:

screenshot
screenshot-1
screenshot-2
screenshot-3
screenshot-4

13 Likes