Hardware testing

We often do not have this board ourselves. Community testing helps establish what actually works. A successful report is evidence for the maintainer to review, not an automatic compatibility claim.

Board details & configuration
Model
Elecrow CrowPanel advance 2.8 hmi esp32 ai display 320x240
Chip, RAM and flash
ESP32-S3, 512KB SRAM, 8M PSRAM,16M Flash
Display and touch
2.8, 320x240, ft63x6, IC ST7789
Already tried
I've done this configuration via ESP Home: esphome: name: crowpaneloffice friendly_name: CrowPanelOffice build_flags: - "-DBOARD_HAS_PSRAM" on_boot: priority: -10 then: - delay: 3s - lambda: |- ESP_LOGI("boot", "Setting initial image URLs from sensors"); - component.update: my_display esp32: board: esp32-s3-devkitc-1 framework: type: esp-idf advanced: execute_from_psram: true sdkconfig_options: CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: y CONFIG_ESP32S3_DATA_CACHE_64KB: y CONFIG_SPIRAM_FETCH_INSTRUCTIONS: y CONFIG_SPIRAM_RODATA: y psram: mode: octal speed: 80MHz spi: clk_pin: GPIO42 mosi_pin: GPIO39 i2c: sda: GPIO15 scl: GPIO16 frequency: 400kHz scan: true touchscreen: - platform: ft63x6 id: panel_touch address: 0x38 display: my_display update_interval: 50ms on_touch: then: - lambda: |- ESP_LOGI("touch", "tap: x=%d y=%d raw_x=%d raw_y=%d", touch.x, touch.y, touch.x_raw, touch.y_raw); // Handle bottom taskbar navigation directly from the reported touch coordinates. if (touch.y >= 150 && touch.y <= 239) { // Touch X is significantly left-shifted on this panel; compensate for easier icon targeting. int nav_x = touch.x + 58; if (nav_x < 0) nav_x = 0; if (nav_x > 319) nav_x = 319; int target_page = -1; if (nav_x <= 63) { target_page = 0; } else if (nav_x <= 127) { target_page = 1; } else if (nav_x <= 191) { target_page = 2; } else if (nav_x <= 255) { target_page = 3; } else { target_page = 4; } ESP_LOGI("display", "Taskbar touch candidate: x=%d adj_x=%d y=%d -> page %d", touch.x, nav_x, touch.y, target_page); const uint32_t now = millis(); if (now - id(last_page_switch_time) < 350) { ESP_LOGD("display", "Taskbar touch ignored (debounce), last switch was %u ms ago", now - id(last_page_switch_time)); return; } if (id(display_page) != target_page) { id(last_page_switch_time) = now; id(display_page) = target_page; id(my_display).update(); ESP_LOGI("display", "Taskbar touch switched to page %d", target_page); } else { ESP_LOGI("display", "Taskbar touch matched current page %d; no switch needed", target_page); } } else { ESP_LOGD("display", "Touch outside taskbar band: x=%d y=%d", touch.x, touch.y); } calibration: x_min: 0 x_max: 239 y_min: 0 y_max: 319 transform: swap_xy: true mirror_x: true mirror_y: false display: - platform: mipi_spi id: my_display model: ST7789V cs_pin: GPIO40 dc_pin: GPIO41 reset_pin: GPIO3 dimensions: width: 240 height: 320 color_order: bgr invert_colors: true rotation: 270 data_rate: 20MHz spi_mode: MODE0 draw_rounding: 1 lambda: |- const auto COLOR_WHITE = Color(255, 255, 255); const auto COLOR_BLACK = Color(0, 0, 0); const auto COLOR_RED = Color(255, 0, 0); const auto COLOR_GREEN = Color(0, 255, 0); const auto COLOR_BLUE = Color(0, 0, 255); const auto COLOR_YELLOW = Color(255, 255, 0); const auto COLOR_ORANGE = Color(255, 165, 0); auto color_off = COLOR_WHITE; auto color_on = COLOR_BLACK; The touch is a bit off it seems though.
Configuration status
working
View shared configuration
esphome:
  name: crowpaneloffice
  friendly_name: CrowPanelOffice
  build_flags:
    - "-DBOARD_HAS_PSRAM"
  on_boot:
    priority: -10
    then:
      - delay: 3s
      - lambda: |-
          ESP_LOGI("boot", "Setting initial image URLs from sensors");
      - component.update: my_display

substitutions:
  ha_base_url: "http://homeassistant.local:8123"

esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: esp-idf
    advanced:
      execute_from_psram: true
    sdkconfig_options:
      CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: y
      CONFIG_ESP32S3_DATA_CACHE_64KB: y
      CONFIG_SPIRAM_FETCH_INSTRUCTIONS: y
      CONFIG_SPIRAM_RODATA: y

psram:
  mode: octal
  speed: 80MHz

logger:
  level: INFO
  logs:
    http_request: ERROR

captive_portal:

http_request:

api:
  encryption:
    key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  on_client_connected:
    then:
      - script.execute: force_ha_entity_refresh

ota:
  - platform: esphome
    password: "7e86936b45b72df03857d2d2a5df92ff"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  ap:
    ssid: "Crowpaneloffice Fallback Hotspot"
    password: "xxxxxxxxxxxx"

spi:
  clk_pin: GPIO42
  mosi_pin: GPIO39

i2c:
  sda: GPIO15
  scl: GPIO16
  frequency: 400kHz
  scan: true

touchscreen:
  - platform: ft63x6
    id: panel_touch
    address: 0x38
    display: my_display
    update_interval: 50ms
    on_touch:
      then:
        - lambda: |-
            ESP_LOGI("touch", "tap: x=%d y=%d raw_x=%d raw_y=%d", touch.x, touch.y, touch.x_raw, touch.y_raw);

            // Handle bottom taskbar navigation directly from the reported touch coordinates.
            if (touch.y >= 150 && touch.y <= 239) {
              // Touch X is significantly left-shifted on this panel; compensate for easier icon targeting.
              int nav_x = touch.x + 58;
              if (nav_x < 0) nav_x = 0;
              if (nav_x > 319) nav_x = 319;
              int target_page = -1;

              if (nav_x <= 63) {
                target_page = 0;
              } else if (nav_x <= 127) {
                target_page = 1;
              } else if (nav_x <= 191) {
                target_page = 2;
              } else if (nav_x <= 255) {
                target_page = 3;
              } else {
                target_page = 4;
              }

              ESP_LOGI("display", "Taskbar touch candidate: x=%d adj_x=%d y=%d -> page %d", touch.x, nav_x, touch.y, target_page);

              const uint32_t now = millis();
              if (now - id(last_page_switch_time) < 350) {
                ESP_LOGD("display", "Taskbar touch ignored (debounce), last switch was %u ms ago", now - id(last_page_switch_time));
                return;
              }

              if (id(display_page) != target_page) {
                id(last_page_switch_time) = now;
                id(display_page) = target_page;
                id(my_display).update();
                ESP_LOGI("display", "Taskbar touch switched to page %d", target_page);
              } else {
                ESP_LOGI("display", "Taskbar touch matched current page %d; no switch needed", target_page);
              }
            } else {
              ESP_LOGD("display", "Touch outside taskbar band: x=%d y=%d", touch.x, touch.y);
            }
    calibration:
      x_min: 0
      x_max: 239
      y_min: 0
      y_max: 319
    transform:
      swap_xy: true
      mirror_x: true
      mirror_y: false

display:
  - platform: mipi_spi
    id: my_display
    model: ST7789V
    cs_pin: GPIO40
    dc_pin: GPIO41
    reset_pin: GPIO3
    dimensions:
      width: 240
      height: 320
    color_order: bgr
    invert_colors: true
    rotation: 270
    data_rate: 20MHz
    spi_mode: MODE0
    draw_rounding: 1
    lambda: |-
        const auto COLOR_WHITE = Color(255, 255, 255);
        const auto COLOR_BLACK = Color(0, 0, 0);
        const auto COLOR_RED = Color(255, 0, 0);
        const auto COLOR_GREEN = Color(0, 255, 0);
        const auto COLOR_BLUE = Color(0, 0, 255);
        const auto COLOR_YELLOW = Color(255, 255, 0);
        const auto COLOR_ORANGE = Color(255, 165, 0);
        auto color_off = COLOR_WHITE;
        auto color_on = COLOR_BLACK;

        // Helper to print text with word-wrap at widget boundary
        auto print_wrapped_text = [&](int x, int y, int max_w, int line_h, esphome::font::Font *font, Color color, TextAlign align, const char* text) {
          if (!text || max_w <= 0) return;
          int cx = x;
          int cy = y;
          std::string line;
          std::string word;
          const char* p = text;
          while (*p) {
            // SANITIZATION: Treat newlines, carriage returns, and tabs as spaces for flow
            bool is_space = (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t');
            if (is_space) {
              if (!word.empty()) {
                int ww, wh, wbl, wx;
                font->measure(word.c_str(), &ww, &wx, &wbl, &wh);
                int lw = 0, lx;
                if (!line.empty()) { font->measure(line.c_str(), &lw, &lx, &wbl, &wh); int sw, sx, sbl, sh; font->measure(" ", &sw, &sx, &sbl, &sh); lw += sw; }
                if (lw + ww > max_w && !line.empty()) {
                  it.print(cx, cy, font, color, align, line.c_str());
                  cy += line_h;
                  line = word;
                } else {
                  if (!line.empty()) line += " ";
                  line += word;
                }
                word.clear();
              }
            } else {
              word += *p;
            }
            p++;
          }
          if (!word.empty()) {
            int ww, wh, wbl, wx;
            font->measure(word.c_str(), &ww, &wx, &wbl, &wh);
            int lw = 0, lx;
            if (!line.empty()) { font->measure(line.c_str(), &lw, &lx, &wbl, &wh); int sw, sx, sbl, sh; font->measure(" ", &sw, &sx, &sbl, &sh); lw += sw; }
            if (lw + ww > max_w && !line.empty()) {
              it.print(cx, cy, font, color, align, line.c_str());
              cy += line_h;
              line = word;
            } else {
              if (!line.empty()) line += " ";
              line += word;
            }
          }
          if (!line.empty()) {
            it.print(cx, cy, font, color, align, line.c_str());
          }
        };

1 owner has volunteered to test.

Sign in to volunteer

Discussion 0

Add a comment

Start the conversation

Share an example, ask a question or explain how you would use this.

Add your thoughts, a screenshot or a useful link.

Markdown & basic HTML
Paste or drop images Β· URLs on their own line become previews0 / 10,000
Create your account to join in

We need a verified email address to reach you about your contribution. Your address stays private.

Continue with GitHub

Your draft stays in this tab. Return here after verification.