For windows command line isn’t it as simple as the first (windows) section here :
https://esphome.io/guides/installing_esphome/
I use Linux as per that guide BTW and everything works as expected.
For windows command line isn’t it as simple as the first (windows) section here :
https://esphome.io/guides/installing_esphome/
I use Linux as per that guide BTW and everything works as expected.
Thanks for the suggestion!
I’ve already successfully installed ESPHome following those instructions - Python and ESPHome are installed and working fine. I can run esphome version without any issues.
The problem occurs during compilation, not during installation. Specifically:
esphome compile nesp.yaml - it starts compilingThe exact error:
INFO Installing tools via idf_tools.py (this may take several minutes)...
ERROR idf_tools.py installation failed (rc=1). Tail:
96%
97%
98%
99%
Done
INFO Installing tools via idf_tools.py (this may take several minutes)...
This happens on:
All three environments fail at the exact same point - when idf_tools.py tries to install ESP-IDF framework tools. The download reaches 96-99% then fails and retries indefinitely.
I’ve also tried:
The issue appears to be specific to ESP-IDF tools download, not ESPHome installation itself. Has anyone successfully compiled neo-nesp (or any ESP-IDF based ESPHome project) on Windows recently?
I got it working using windows. I needed to install python 3.11.9 as I couldn’t get it to work with the current release. Also git needs to be installed (as per the link from my previous post) and its location in your path.
Next you need to make sure there is no space in your platformIO path or you will get a corresponding error. see : Error: Detected a whitespace character in project paths - #7 by xumixu - PlatformIO IDE - PlatformIO Community you can set a (Windows) environment variable “PLATFORMIO_CORE_DIR ” to change the directory to be used.
First compile took a long time for tools installation probably due to virus/malware scanning in the background.
Thanks so much for taking the time to share your solution! I really appreciate it.
I’ve followed all your suggestions on a fresh Windows Surface Pro:
Python 3.11.9 - Installed from python.org
Git - Installed and verified in PATH (git version 2.51.2.windows.1)
PLATFORMIO_CORE_DIR - Set to C:\platformio (no spaces)
Windows Defender - Disabled real-time protection and added exclusion for C:\platformio
ESPHome - Installed via pip (esphome version 2025.10.5)
Despite following all your steps, compilation consistently fails with:
INFO Installing tools via idf_tools.py (this may take several minutes)...
ERROR idf_tools.py installation failed
Then CMake errors:
CMake Error: The CMAKE_C_COMPILER (xtensa-esp32s3-elf-gcc) is not a full path
and was not found in the PATH.
The root issue appears to be that the pioarduino toolchain ZIP is corrupt - when downloaded, it only contains package.json and tools.json, with no actual compiler binaries.
I can see PlatformIO trying to download:
https://github.com/pioarduino/registry/releases/download/0.0.1/xtensa-esp-elf-14.2.0_20241119.zip
The download shows 100% complete, but when extracted, there are no binaries - just metadata files.
C:\platformio\packages\toolchain-xtensa-esp-elf.../bin/xtensa-esp32s3-elf-gcc.exeEven when I lock the directory or add the toolchain to PATH, PlatformIO insists on downloading the corrupt pioarduio version during compilation.
Since you got it working, could you help me understand:
dir C:\platformio\packages\toolchain-xtensa-esp-elf\bin
Does it have xtensa-esp32s3-elf-gcc.exe?
platform: line in nesp.yaml? Mine currently points to: platform: https://github.com/pioarduino/platform-espressif32/releases/download/54.03.21-2/platform-espressif32.zip
I’m particularly interested in:
I’ve tried this on three different devices now (Windows PC, Surface, Home Assistant) and all hit the same corrupt toolchain issue. Since you got it working, there must be something different about your setup or approach.
Any help would be greatly appreciated! This has been going on for days now and I’m at my wit’s end.
Thanks again for your help!
I can answer all the questions in your last post but I suspect the problem may be your config(s). I see you are trying to compile nesp.yaml but I don’t see that file in any of the 3 githubs linked in this thread. Can you please post your config(s) as attachments? Then I can try to build them at my end. If you want to try building my configs they are in my github linked a few posts up. What hardware are you using BTW?
Do you have basic instructions for compiling/building in esphome? Looks like the pioarduino release package for 6.8.1 isn’t available and seems like the LVGL components causes errors on the current stable release of esphome.
EDIT - fully working - this is great!
Using a 3D printed mount which hides the wires and I soldered 5V+GND directly to the unused pads on the breakout board so I can avoid the visible USB cable sticking out the side.
@wineds is there a way to ignore the first touch/rotate input when the backlight is off? I have an automation to turn off the lights after 60 seconds but the first click jumps into the menu which is a bit awkward. Thanks for the awesome code, I had very few issues adding it to ESPhome and compiling that way.
Have you tried launching the ESPhome docker container in a WSL image and using that? It built easily on HAOS and I imagine regular ESPhome is the same story if you are on Linux instead of Windows.
Thanks but its @kto (and @veli) you really need to be thanking as you appear to be using his code on your rotary display. My code is for the waveshare 2.1 touch display.
No I haven’t. I use a terminal window on linux as per here : Installing ESPHome Manually - ESPHome - Smart Home Made Simple
It builds quickly on a modern laptop and works out of the box.
Oops! Got my links confused!
Thanks @veli and @kto - any tips on using the first input event purely to enable the backlight?
Yeah, it’s so much easier on Linux than trying to compile code under Windows.
Figured out how to ignore the first press/rotate if the backlight is off IMHO this makes it a nicer experience if using a timeout to turn off backlight:
binary_sensor:
### CENTRE PUSH BUTTON
- platform: gpio
name: Button
id: push_button
icon: mdi:circle-outline
internal: true
pin:
number: 3
mode: INPUT
inverted: true
ignore_strapping_warning: true
on_press:
# - script.execute:
# id: vibrate
# length_ms: 10
- light.turn_on: backlight
- if:
condition:
and:
- lvgl.is_paused
- light.is_on: backlight
then:
- lvgl.resume:
- lvgl.widget.redraw:
- if:
condition:
and:
- light.is_on: backlight
# only when on the main page
- lambda: 'return strcmp(id(active_lvgl_page).c_str(), "main_page") == 0;'
then:
- script.execute: goto_menu_page
- platform: status
name: Status
button:
- platform: restart
name: Restart
disabled_by_default: True
sensor:
- platform: uptime
name: Uptime
disabled_by_default: True
### ROTARY ENCODER
- platform: rotary_encoder
name: Rotary Encoder
id: rotary
icon: mdi:cached
internal: true
pin_a:
number: 6
inverted: true
mode: INPUT
pin_b:
number: 5
inverted: true
mode: INPUT
on_value:
- light.turn_on: backlight
- if:
condition:
and:
- light.is_on: backlight
# turn ON when when on main page and OFF
- lambda: 'return strcmp(id(active_lvgl_page).c_str(), "main_page") == 0 && strcmp(id(hvac_mode).state.c_str(), "off") == 0;'
then:
- homeassistant.action:
action: climate.turn_on
data:
entity_id: ${climate_entity}
- if:
condition:
and:
- light.is_on: backlight
- lvgl.is_paused
then:
- lvgl.resume:
- lvgl.widget.redraw:
on_clockwise:
- if:
condition:
and:
- light.is_on: backlight
# set temp++ when on main page and not OFF or FAN
- lambda: 'return strcmp(id(active_lvgl_page).c_str(), "main_page") == 0 && strcmp(id(hvac_mode).state.c_str(), "off") != 0 && strcmp(id(hvac_mode).state.c_str(), "fan_only") != 0;'
then:
- homeassistant.action:
action: climate.set_temperature
data:
entity_id: ${climate_entity}
temperature: !lambda return id(set_temperature).state + 0.5;
on_anticlockwise:
- if:
condition:
and:
- light.is_on: backlight
# set temp-- when on main page and not OFF or FAN
- lambda: 'return strcmp(id(active_lvgl_page).c_str(), "main_page") == 0 && strcmp(id(hvac_mode).state.c_str(), "off") != 0 && strcmp(id(hvac_mode).state.c_str(), "fan_only") != 0;'
then:
- homeassistant.action:
action: climate.set_temperature
data:
entity_id: ${climate_entity}
temperature: !lambda return id(set_temperature).state - 0.5;
Now I just have to figure out how to set a screen-off timer on the device itself without relying on an external automation.
Generally speaking the correct way to do that is wakeup on release, not press. That way if LVGL is paused the press that happens before the release is ignored.