#bb_paper inclusion in ESPHome
267 messages · Page 1 of 1 (latest)
thanks
I'm having trouble with the codegen step. I'm getting some odd names coming out and I have no idea where the problem is 🙁
Do you have a log? Is the code on gh?
It's currenty being rejected by github because of the ESPHome clang-format rule. I want to fix the bugs before I make it pretty.
The namespace/class/codegen step is completely opaque to me and it's generating strange results
src/main.cpp: In function 'void setup()':
src/main.cpp:603:55: error: invalid new-expression of abstract class type 'esphome::epaper::BB_EPaperBase'
603 | epaper_bb_epaperbase_id = new epaper::BB_EPaperBase();
| ^
In file included from src/esphome.h:18,
from src/main.cpp:3:
src/esphome/components/bb_epaper/bb_epaperbase.h:11:7: note: because the following virtual functions are pure within 'esphome::epaper::BB_EPaperBase':
11 | class BB_EPaperBase : public display::DisplayBuffer,
| ^~~~~~~~~~~~~
my display.py:
BB_EPaperBase = epaper_ns.class_(
"BB_EPaperBase", cg.PollingComponent, spi.SPIDevice, display.DisplayBuffer
)
CONFIG_SCHEMA = cv.Schema(
display.FULL_DISPLAY_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(BB_EPaperBase),
...
relevant part
I can create a new repo with just my component
I don't understand how the class name nesting gets so twisted up by codegen
I normally work in C, so this C++ syntax is quite confusing
it looks like something wrong with the way I'm extending the Display class
Did you override all the pure virtuals from display::DisplayBuffer? Ie something like:
void draw_absolute_pixel_internal(int x, int y, Color color) override;
int get_height_internal() override;
int get_width_internal() override;
display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_BINARY; }
Or are any of those in the header but not implemented in the cpp?
Your schema is defining the id as the base class, so when you generate the variable in the to_code, that's the class it tries to create which won't work.
I assume you have classes for each display?
One class for all displays, each display gets an enumerated value
I have no idea what ID and base class means in this sense
I thought it would be relatively simple to write a wrapper class over bb_epaper
I had to write some new features such as I/O through function pointers to get the I/O to work in ESPHome
I don't know how to "gen" the code to make this simple
I don't need components or subclasses
I wondered how well this was going to integrate when I first heard about it...
should be quite straightforward if not for the class twist-up
I'll create a public repo for the code, hang on
Is there some easy explanation to connect the dots between the Python and the C++ that gets generated?
It's quite direct. It's the to_code that generates it.
right, but Python->C++ syntax makes no sense
if it's just the missing virtual functions, then that should be easy to solve
var = cg.new_Pvariable(config[CONF_ID]) creates a new variable with the class defined in CONF_ID, so BB_EPaperBase in this case.
You can see the generated code in main.cpp.
none of that syntax makes sense to me. What kind of programmer would work in that world ?
I don't see any issues with it... 🤷♂️
so you're a Python programmer?
yes, and whatever other languages 🙂
I never work in Python, and don't get into the weeds of C++, so it doesn't make sense to me
esphome gets into deep details of both.
I'm less interested in becoming an expert in this subject and more interested in just getting this simple project working
my time is very limited and the frustration increases exponentially the more time I have to dedicate to this
Are all the virtuals implemented? If your code is on GH it will be helpful.
If pure virtuals are not implemented you will get that error when it tries to create the object in main.cpp
fixing now...
I'm looking at the ST7789 implementation and it doesn't have a couple of the virtual functions that my build is complaining are missing
Thanks @pseudo fossil & @raven isle most errors are resolved now. I'll let you know if I have any more questions.
Hi @raven isle closer, but still not working
my code all compiles without errors, but the display component is never called
- platform: bb_epaper
id: waveshare_esp32s3
cs_pin: GPIO11
dc_pin: GPIO10
busy_pin: GPIO8
reset_pin: GPIO9
model: ep154_200x200
lambda: |-
it.print(0, 0, id(Roboto_10), "Hello World!");
I added logging to the main methods and they never get printed
Am I missing something obvious?
(WiFi succeeds)
[13:09:39.476][I][safe_mode:054]: Boot seems successful; resetting boot loop counter
Into setup? Are you using usb / serial? Setup is run before wifi connects so need to use usb.
I'm using USB
I added logging to all main methods
nothing ever prints
initial log:
INFO Successfully uploaded program.
INFO Starting log output from /dev/cu.usbmodem113201 with baud rate 115200
[13:03:39.425][I][app:084]: Running through setup()
[13:03:39.426][V][app:085]: Sorting components by setup priority
[13:03:39.427][V][component:201]: Setup wifi
[13:03:39.444][C][wifi:373]: Starting
Code in gh is up to date?
not yet; I'll poke through the main.cpp to see if I can figure out the issue
I would suggest pushing changes, even in its broken state so we can view exactly the current state. it is extremely hard to help and debug without looking at the code and causes more delays
I will - I need to get it as far as I can first. It's starting to work.
hi @raven isle I've made a lot of progress with the bb_epaper component, but there are still some issues to resolve.
The initialization and update methods seem to be working, but my yaml lamba doesn't result in any fill or pixel function calls
- platform: bb_epaper
update_interval: 30s
id: waveshare_esp32s3
cs_pin: GPIO11
dc_pin: GPIO10
busy_pin: GPIO8
reset_pin: GPIO9
model: ep154_200x200
lambda: |-
it.fill(id(Color::BLACK));
it.print(20, 60, id(medium), "This is a test");
it compiles and runs without any errors. I put log print statements in the fill() and draw_absolute_pixel_internal() methods, but they're never called.
Is your code up to date in gh?
can you think of a reason that the fill and pixel methods wouldn't get called?
possible C++ override syntax issue?
I'll push the component source; hang on
ok @raven isle newest component code is here:
Very hard to debug something without seeing the code. Can always create a dev branch and push to that
see above - code is now visible
Looks like you are missing https://github.com/esphome/esphome/blob/dev/esphome/components/st7735/st7735.cpp#L294
right now I'm getting successful updates, but the display is blank
aren't those internal methods specific to that display component?
the call to update() from ESPHome is succeeding with my library
do_update_ is some method from the display component, you inherit from DisplayBuffer which inherits from Display
still don't follow you. It's not a problem with update
Seems like you should be calling it but I havent done much display stuff
trailing underscore in the name indicates it's private to that repo and not an override method
It is protected. You inherited from display so that is part of your class
I am pretty sure that calls the lambda
Without it nothing will get rendered
I think you have it backwards
Did you try it?
that method is protected because of the extra layers of hierarchy of that library
no need - update is getting called and succeeding in my library
update gets called every 30s as it should
that's not the issue
Yes I know. Add this to your update function
makes no sense because the fill and pixel functions are never called
they would need to be called BEFORE the update
even if it happens once
if you look in the waveshare display driver there is no update_() method
ok, I'll try
I see - hang on
The lambda is called on this line https://github.com/esphome/esphome/blob/dev/esphome/components/display/display.cpp#L697 so without that call nothing is rendered
ah - thanks for being patient
compiling...
makes sense - it allows the display component to skip a redraw if necessary
thanks @pseudo fossil - working now 🙂
Now that it appears to be working, the bigger question is how we should present it to the users.
In it's current form, you specific the SPI connection and the panel type.
But... I've created a much simpler way for IoT devices with built in displays. For example, the Elecrow CrowPanel devices can be used with just a single line of code:
epaper.begin(EPD_CROWPANEL29);
The configuration is contained within bb_epaper, so the user doesn't have to fumble with GPIO connections
It currently supports 14 products like that
what do you think @raven isle @pseudo fossil ? I currently access SPI directly, but I could probably adapt it to use the ESPHome SPI component. Maybe I can create a second component for use with these products or a generic one for everything else.
one last question...
to enable either the iot device name or raw panel, I need SPI to be optional for the display component. Is that possible?
@raven isle
when I use the iot device name, all hardware initialization and communication is handled by my library
I would like the user to not have to define the SPI bus
or will that require a new ESPHome component?
I think that's going to be a problem.
I got it working
- platform: bb_epaper_iot
update_interval: 60s
id: test_epd
model: EPD_CROWPANEL29
lambda: |-
it.fill(id(Color::BLACK));
it.print(0, 0, id(medium), "bb_epaper test");
it.printf(0, 80, id(medium), "one line config!");
I mean I think it will be a problem getting it accepted.
Hey @raven isle how do you like no-flicker e-paper for ESPHome? 🙂
I'm experimenting with a default update type of partial updates with a fast update every 16 updates to eliminate any possible ghosting
@steep quarry I need some feedback on these decision. Should I expose the refresh type (full, fast, partial) or just do the least flickery way all the time?
(see youtube video above)
Hi @raven isle I'm working on supporting color e-paper displays and noticed something odd. The Display class call to get_display_type() isn't called (I put a log print statement in it). Is this not really needed?
I'm thinking that I should just do a best match of the requested color.
It is called in the test card code but needs to be implemented as it is pure virtual
I believe if you do something like this it will be called:
display:
- platform: xxx
show_test_card: true
ok
I would expose them all
nice! what board is that?
Waveshare ESP32-S3-ePaper-3.97"
Hey @tropic musk Is the work in a state where it could be opened as a PR so we can see it with the ESPHome codebase?
It's curently in a separate repo that's easy to manually copy into the /components folder to test. Probably not ready to merge yet
I'm rewriting my bb_temperature library to work with the ESPHome I2C component and then I'll add my bb_captouch (pretty much covers all common capacitive touch screens)
I would appreciate any and all feedback on the bb_epaper work so far.
It already is a major step up from the waveshare library because it allows you to more easily choose the type of panel and the update mode
I created a second component (bb_epaper_iot) that simplifies things further for supported ESP32+EPD products like the ones from Waveshare. However, it currently uses the Arduino or ESP-IDF SPI library directly instead of using the one in ESPHome.
Have you seen external_components?
It lets you supply components from an external source: https://esphome.io/components/external_components/
Exactly the same as the built-in ones.
Just wasnt sure given:
easy to manually copy into the /components folder to test
I'll redo the file structure to work as an external component
@steep quarry I'm finally sitting down to work on making my component conform to the ESPHome coding standards. I've got clang-format and clang-tidy installed, but I'm not sure if I'm using them correctly. I tried running the scripts (clang-format and clang-tidy). Both give errors
The clang-format script says that I may not have it installed in the environment. It is installed, yet shows this when I pass --version as the only parameter:
zsh: /Users/laurencebank/Projects/esphome/venv/bin/clang-format: bad interpreter: /Users/laurencebank/Projects/esphome/venv/bin/python3: no such file or directory
clang-format version 22.1.3
Running the clang-tidy script gives these errors:
File "/Users/laurencebank/Projects/esphome/esphome/components/bb_epaper/../../../script/clang-tidy", line 357, in <module>
sys.exit(main())
File "/Users/laurencebank/Projects/esphome/esphome/components/bb_epaper/../../../script/clang-tidy", line 285, in main
idedata = load_idedata(args.environment)
File "/Users/laurencebank/Projects/esphome/script/helpers.py", line 546, in load_idedata
stdout = subprocess.check_output(
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/subprocess.py", line 424, in check_output
return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/subprocess.py", line 505, in run
with Popen(*popenargs, **kwargs) as process:
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/subprocess.py", line 951, in __init__
self._execute_child(args, executable, preexec_fn, close_fds,
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/subprocess.py", line 1821, in _execute_child
raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'pio'
hmm - I just set up a new machine and it's missing some things. Let me work on this a bit more...
script/clang-tidy --all-headers --environment esp32-arduino-tidy and script/clang-tidy --all-headers --environment esp32-idf-tidy --grep USE_ESP_IDF
have to do source venv/bin/activate first
I did activate, but something else is broken
just running esphome from the command line gives this:
(venv) laurencebank@4a:5f:88:47:24:de esphome % esphome
zsh: /Users/laurencebank/Projects/esphome/venv/bin/esphome: bad interpreter: /Users/laurencebank/Projects/esphome/venv/bin/python3: no such file or directory
usage: esphome [-h] [-v] [-q] [-l {DEBUG,INFO,WARNING,ERROR,CRITICAL}]
[-s key value] [--mdns-address-cache MDNS_ADDRESS_CACHE]
[--dns-address-cache DNS_ADDRESS_CACHE] [--testing-mode]
[--version]
command ...
bad interpreter?
hang on, new machine problems - let me create a new venv
script/setup
source venv/bin/activate
script/clang-tidy --all-headers --environment esp32-arduino-tidy
script/clang-tidy --all-headers --environment esp32-idf-tidy --grep USE_ESP_IDF
it was that the new machine's python3 was in a different spot, but I had restored the esphome repo from the old machine
new python weirdness
(venv) laurencebank@4a:5f:88:47:24:de esphome % script/setup
Using Python 3.9.6 environment at: venv
Checked 2 packages in 11ms
Using Python 3.9.6 environment at: venv
× No solution found when resolving dependencies:
╰─▶ Because only esphome[dev]==2026.1.0.dev0 is available and the current
Python version (3.9.6) does not satisfy Python>=3.11.0,<3.14, we can
conclude that all versions of esphome[dev] cannot be used.
And because you require esphome[dev], we can conclude that your
requirements are unsatisfiable.
Yeah 3.9 is too old need >=3.11
strange, brew installed 3.14
how do I get the brew version to be seen in the esphome environment?
natively how?
Clone the repo and just run the setup script?
what repo?
The esphome repo
that has no bearing on the python3 problem
I dont know what brew has to do with this but I have never used it.
homebrew has python3 3.14 installed, but the system still references python 3.9.6
I need to fix the path order
@pseudo fossil thanks for your help. I had to switch the path order of zsh for it to find the correct Python version. Now things are working.
@pseudo fossil closer... still getting errors from the clang-tidy script and parameters you provided:
Total cpp files to check: 1
Added all-include header file, new total: 2
Final files to process:
/Users/laurencebank/Projects/esphome/.temp/all-include.cpp
bb_epaperbase.cpp
Loading IDE data for environment 'esp32-arduino-tidy'...
NotPlatformIOProjectError: Not a PlatformIO project. `platformio.ini` file has not been found in current working directory (/Users/laurencebank/Projects/esphome/esphome/components/bb_epaper). To initialize new project please use `platformio project init` command
platformio.ini is in the root dir: https://github.com/esphome/esphome/blob/dev/platformio.ini
run it from the root dir
sorry, can you clarify? I'm running it in the directory with the files to modify. How would the command line look for your idea?
This back and forth makes me think this would be a good topic to add to the developer documentation. I couldn't find any useful info there.
You cant run it on a single component, run it in the root esphome folder (I gave the commands above)
Most people just submit a PR and have CI run it
script/setup
source venv/bin/activate
script/clang-tidy --all-headers --environment esp32-arduino-tidy
script/clang-tidy --all-headers --environment esp32-idf-tidy --grep USE_ESP_IDF
Can you describe the PR/CI process? When I tried to create a new branch with this code, Github blocked it because it didn't conform to the code style rules.
So you're saying to just use the error info from trying to create a PR to make the edits instead of letting clang-tidy do them for me?
Yes there is also a pre commit check.
You will need to fix those errors first
I'm still getting errors just running the script
File "/Users/laurencebank/Projects/esphome/script/clang-tidy", line 357, in <module>
sys.exit(main())
~~~~^^
File "/Users/laurencebank/Projects/esphome/script/clang-tidy", line 285, in main
idedata = load_idedata(args.environment)
File "/Users/laurencebank/Projects/esphome/script/helpers.py", line 546, in load_idedata
stdout = subprocess.check_output(
["pio", "run", "-t", "idedata", "-e", environment]
)
File "/opt/homebrew/Cellar/[email protected]/3.14.4/Frameworks/Python.framework/Versions/3.14/lib/python3.14/subprocess.py", line 473, in check_output
return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
**kwargs).stdout
^^^^^^^^^
File "/opt/homebrew/Cellar/[email protected]/3.14.4/Frameworks/Python.framework/Versions/3.14/lib/python3.14/subprocess.py", line 578, in run
raise CalledProcessError(retcode, process.args,
output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '['pio', 'run', '-t', 'idedata', '-e', 'esp32-arduino-tidy']' returned non-zero exit status 1.
ah - new error: Loading IDE data for environment 'esp32-arduino-tidy'...
ERROR: Python version must be between 3.10 and 3.13.
The current version of Python on Homebrew is 3.14 and this seems to cause a problem for the script
3.14 works unless you are on an old version
old version of what?
I just did a git pull to get the latest. How can I tell
?
New machine - I just installed epshome
I ran it today on 3.14 and it was fine
This experience reinforces my belief that depending on Python for these tools creates a huge time expense for everyone 🙁
Submit a draft pr it will run it
I'd like to understand this roadblock
Homebrew seems to mess things up, python is fine
I'm using a newly installed esphome and the repo is up to date
I would assume the inverse
Python is always having trouble with version conflicts - it's a feature
We have so many issues where people are using homebrew and can't build
what's the "golden" OS to use for ESPHome? Linux?
That is what I use. No brew. Just python
homebrew is a package manager like apt, nothing to do with interfering in use of the tools
Well people try to install ESPHome with it. It messes with the paths.
I don't want to create extra work for you. It shouldn't take so much effort just to run clang-tidy
I can try this on my Linux laptop
I gave the commands above. I tested them and they work.
That's not helpful. If it's only designed for Linux, then ok.
I don't have a mac to try it on
Does anyone test it on MacOS or Windows?
I know Nick runs on a mac, maybe Clyde does too. But most people just get CI to run it
Almost no one runs it locally
the build system has worked fine so far on MacOS, it just seems to be an issue with running the clang-tidy script
when you say "get CI to run it", can you elaborate?
By creating a PR
my last try creating a PR went south. Lots of errors and a rejection. How is the work flow supposed to go?
Yes there is a pre commit check before you can create one.
right
You have to fix those before you create a PR
telling me "code rejected for formatting error" isn't actionable
Can you paste the full error. Normally it is very clear
Or it auto fixes the style and can just add the changes and try again
how can I enable "auto fix"?
It normally does that
I tried to push to a new branch and it got rejected there with no option to fix anything
Paste the full error message
And command
Did you fork the repo or just clone it?
I tried cloning, creating a new branch and that's where I got rejected
so I forked it and the code is sitting in my fork
let me try
You are not an ESPHome maintainer so don't have permissions to create a branch in the actual repo. Have to create one in your fork and create a PR there
I need to reset everything, I have different code in the fork
creating a new branch on my fork is giving some formatting errors
ruff (legacy alias)......................................................Failed
- hook id: ruff
- files were modified by this hook
Found 2 errors (2 fixed, 0 remaining).
ruff format..............................................................Passed
flake8...................................................................Passed
don't commit to branch...................................................Passed
fix end of files.........................................................Passed
trim trailing whitespace.................................................Failed
- hook id: trailing-whitespace
- exit code: 1
- files were modified by this hook
Fixing esphome/components/bb_epaper/bb_epaperbase.cpp
pyupgrade................................................................Passed
yamllint.............................................(no files to check)Skipped
clang-format.............................................................Failed
- hook id: clang-format
- files were modified by this hook
pylint...................................................................Passed
Update clang-tidy hash...............................(no files to check)Skipped
looks like it tried to fix them
That looks good
branch created
Perfect, can now create a PR
Will have an option there (if you recently pushed) or under your fork
the PR was using the wrong branch. Not sure how to make it work now