Open LordMike opened 1 year ago
I've found that the actual compilation is handled by platformio
, which means this idea either has to:
platformio
to share the output. But as I understand it, each esphome device is a separate environment, and as such it isn't advisable to share the build outputs.platformio
, do the hashing and copying of known outputsI've also realized that the reason there are different environments is due to the different target platforms (esp82xx and whatnot). I think this is still manageable, by making the cache location dependent on these settings. If we know the list of settings that could change the build output, we can hash those together and add it to our cache directory, something like this:
cache_dir = "/esphome_cache/"
cache_dir += hash(settings.esp8266) + "/"
This way, anything changed in the esp8266:
yaml section will produce different cache directories.
I've found that there is a platformio config for each device, so perhaps the cache_dir can be set here, given the hash above.
I've hacked the writer.py
to set build_cache_dir = /esphome_cache/
in the platformio.ini
. I found that it's generated every time I build, so I couldn't just edit the file. I'll try building two identical devices, and see if it works out.
-- later
From reading a discussion, it seems that maybe PIO will automatically handle different platforms and build arguments, such that the cache can freely be used between different builds and it'll just do the right thing. Maybe this is as simple as just setting the cache directory.
-- later
So my testing shows that for two identical devices (a light), the cache did not help between them. Even if the board, settings, everything but the name/api secret were identical, the build_cache_dir
did not take effect (or it did, but it wasn't used between the two).
What did work though, was when I cleaned a previous builds output and built it again. Then the cache was used. So at least there, there will be some gains. I imagine this also works if there is an update from some upstream that would normally force a complete rebuild, the cache can help here.
It seems that for caching between environments (between devices) to work, platformio's caching mechanism needs to ignore the environment name. I'm not sure if doing this would break anything, because it seems that the full commandline they actually run to build stuff, will be enough.
I've created an issue with platformio to improve the build_cache_dir
to work cross-environment.
I hope esphome will add the build_cache_dir
to esphome
platformio.ini's, as this setting is useful regardless of whether it can be used across devices currently. A future update to platformio will hopefully make the cache even better :).
Update: The platformio issue has been closed with no change currently, as it probably needs a much smaller reproducible example. So I'll have to figure out how to make that eventually.
But the crux of it (https://github.com/platformio/platformio-core/issues/4574#issuecomment-1475018136) is that the underlying SCons system (which actually does the build if i understand correctly) does the hashing and determination to use the cache directory and files. It however seems to include the file path in these hashes, which means that two environments in esphome
can never produce the same hash, as they're placed in each their own directories.
That's a bummer! I was hoping to find a way to reduce the time needed to updated multiple devices (my ESPHome dashboard runs in a VM in my NAS, not so much compute power).
Hopefully platformio
and/or SCons will eventually do something about it (I would imagine this improved caching mechanism would also benefit non-ESPHome cases). Thanks for the evaluation!
For now, I'm booting up a temporary ESPHome dashboard on a more powerful device, mounting same config file folders. So far so good!
Would love something like this to be implemented as I have 18 Sonoff S31s with almost identical configurations that take a long time to update as they have to compile every single file from scratch.
I just saw @TMaYaD mention he had ~200 devices in #5821. That must be a pain to update :|
I have my own wrapper around esphome that runs on kubernetes as a cronjob and automatically reconciles devices. All device configs are also tracked on a repo, a la. devops.
Oh wow - that's neat. Any chance this will make its way to the core esphome?
I've been wondering about a "version" as well, being able to determine that the local config is the same as the device's, as to avoid deploying no-ops. This seems to handle this as well :)
Haha Nice Wrapper @TMaYaD! Finally some real steps to manage all the updates of all the ESPHome devices. I like it!
But 200 devices, dude! Is your Wifi still stable?
Just wanted to pipe in again that I made a node-red flow that updates my nodes one by one. It takes a while, but it does complete eventually. It works by listing all the update
entities in HA of the esphome
kind that have an update and then looping through them, waiting for their completion. Once done, it'll notify me.
TL;DR: This issue is a journey I took to find out how to improve caching. Skip to this comment where I used
build_cache_dir
in platformio to improve build speeds.Describe the problem you have/What new integration you would like I've been managing a few identical devices (apart from their identity) for a little while now, and I've been following along when it's been compiling and I see the same code being compiled again and again. This makes sense of course, because it's simpler to see each device as a completely separate unit.
I imagine that in my and many other instances though, at least parts of these files will be identical. It is my impression that the device config is used to substitute values into the source (
cpp
) files, which is then compiled. This could be f.ex. the wifi configuration, which would (at minimum) contain an SSID to connect to. This SSID is the same though, on all my devices. So I'm thinking it should be possible to reuse the compiled output (the.o
file). Note: I've since found that the SSID/Wifi config is actually inmain.cpp
, which just makes the savings greater for the wifi library, as it will be identical "always".If I'm right in assuming the
.cpp
files are modified with the values they need (from the device config), it should be possible to do something like:.cpp
file.cpp
file, f.ex. usingmd5
or something less intensive likexxhash
/somedir/output/HASH.o
.cpp
, and copy the output to/somedir/output/HASH.o
The temporary/cache location can be cleared at will - if it's empty, the sources are compiled again and placed there. Likewise, if there are access timestamps, you can remove the least recently used files in order to keep a rolling set of used files.
There are some drawbacks that I can think of:
esphome
addon served. So one way to handle this is to let the cache directory be an ephemeral location, like a path that isn't mapped to a persistent volume. This way the cache is cleared on each esphome addon update.Please describe your use case for this integration and alternatives you've tried: N/A
Additional context I browsed to my
/data
directory on my esphome addon and checked some of the compiled files. I just grabbed two from the list and found this. I'm in the middle of an update across all devices.So here, we see the hashes of the compiled output of two files:
api_connection.cpp
andproto.cpp
. In the first case, there are 5 distinct versions right now across 14 devices (plus a few I have renamed). For Proto.cpp, there is just the one output.In this case, if the output was cached, I could potentially save 13 compilations of the
proto.cpp
file.