Hey @overeasy !
I’ve loved this project for a long, long time, and I figured it’s time to give back. I’m also a big IPv6 advocate, so this is where I wanted to start. ![]()
TLDR; over the past few weeks I built dual-stack IPv6 support for IoTaWatt, it’s been soaking on my own units, and I’d like to get it upstream. The one decision I need your read on before I prepare anything concrete: how would you want the ESPAsyncTCP dependency handled?
- Vendor the patched source into the IoTaWatt tree.
- Depend on a tagged upstream fork (esphome’s is actively maintained).
- Some other arrangement you’d prefer.
That choice shapes how I’d prepare everything else, so it’s the first thing I want your thoughts on.
The rest is the detail behind that ask:
I run a handful of IoTaWatt units on a dual-stack network at home and wanted them reachable over IPv6 the way they already are over IPv4. What works today, on my units:
- Inbound: the web UI and digest auth over a global IPv6 address (
http://[GUA]/), same behavior as over IPv4. - Outbound: the uploaders (Emoncms, InfluxDB, PVoutput) over IPv6, with a lightweight happy-eyeballs approach: prefer IPv6, fall back to IPv4 on connect failure. Dual-stack endpoints get v6; IPv4-only endpoints (which is all of them today) resolve and connect exactly as they do now.
- SLAAC address acquisition and renewal, with the
localAccesssame-subnet bypass extended to the IPv6 /64 and link-local clients excluded from it.
The most recent build has a multi-day continuous run behind it: heap flat, uploaders posting every cycle, and I OTA’d it to itself over IPv6.
It rides on two dependencies, and both are why I’m asking rather than just sending a PR.
1. ESP8266 core 3.x. IPv6 in lwIP needs the newer core (espressif8266 @4.2.1). I think you moved to core 3 in 2022 and rolled it back after some failures (I pieced the timeline together from the git history). I hit SD-card init failures doing the same migration, and tracked down the mechanism:
- It was not the partition type byte. It was SdFat 2.x requiring exactly two FAT tables, which rejects single-FAT cards. The factory cards from that batch were single-FAT, if I have that right.
- There is a one-line bench reproduction:
mkfs.fat -F 32 -f 1on a spare card reproduces the failure on core 3.x and mounts fine on 2.4.0. - The fix is greiman’s own: current SdFat accepts one or two FAT tables (the mount check is now
fatCount != 1 && fatCount != 2, with matching root-directory and FAT-mirror handling for the single-FAT case). It landed in August 2025 (greiman/SdFat commitcda05731, bundled in with some unrelated exFAT changes), but it hasn’t reached the ESP8266 SdFat fork yet, so for now I backport those few lines at build time.
I’m happy to write that up on its own, since it’s the piece that makes revisiting core 3.x safe.
2. The async TCP stack. The outbound path uses ESPAsyncTCP plus your asyncHTTPrequest. IPv6 needs a small change in ESPAsyncTCP (use IPADDR_TYPE_ANY on connect, and AAAA-capable DNS resolution), plus two small fixes in asyncHTTPrequest (accept bracketed IPv6 literal URLs, and a destructor fix for a connection-cleanup leak that shows up under fast reconnect). The asyncHTTPrequest changes go to your own repo and are small. The ESPAsyncTCP change is the open question from up top: vendor it in-tree, or depend on a tagged upstream fork.
One thing I’ll call out on scope: I intend to keep full IPv6 mDNS (AAAA records over .local) as its own piece of work, separate from the main IPv6 changes. I have it working on my units, a native dual-stack lwIP responder answering A and AAAA over both transports, but it reaches into the lwIP build itself (a rebuilt lwIP), so it’s a deeper change than the rest and better handled on its own. The main IPv6 changes keep the existing IPv4 mDNS, and the device is reachable over IPv6 by address and by AAAA from normal DNS regardless.