Close

Two One-Line Fixes, Or WSS Never Works On ESP32

A project log for VA5 — A $20 Voice Assistant With No Personality Un

A $20 ESP32-S3 voice assistant that ships with no personality. You write one from your phone — no code, no reflash.

udi-tiroshUdi Tirosh 08/24/2026 at 09:430 Comments

If you use ArduinoWebsockets on an ESP32 and you need a secure connection, it does not work. Not "is fiddly" — does not work, and does not tell you why.

What you see is a connection attempt that returns and then simply never becomes a connection. No exception, no useful error, no failed handshake to read. I re-checked the URL, the port, the certificate, the network and the API key before I went looking at the library, which is the wrong order and cost me a weekend.

There are two bugs, and they interlock.

One: SecuredEsp32TcpClient has no setInsecure().

The class wraps WiFiClientSecure but never exposes the one method you need to tell it not to verify a certificate you haven't given it.

    class SecuredEsp32TcpClient : public GenericEspTcpClient<WiFiClientSecure> {
    public:
      void setInsecure() {          // <-- did not exist
        this->client.setInsecure();
      }
      void setCACert(const char* ca_cert) { ... }

Two: the ESP32 branch of upgradeToSecuredConnection() never falls back.

The ESP8266 branch has an else that calls setInsecure() when no key is configured. The ESP32 branch doesn't:

    #elif defined(ESP32)
        if(this->_optional_ssl_ca_cert) {
            client->setCACert(this->_optional_ssl_ca_cert);
        }
        if(this->_optional_ssl_client_ca) {
            client->setCertificate(this->_optional_ssl_client_ca);
        }
        if(this->_optional_ssl_private_key) {
            client->setPrivateKey(this->_optional_ssl_private_key);
        } else {
            client->setInsecure();   // <-- was missing
        }
    #endif

Neither fix works alone. Add the else without adding the method and it won't compile — there's nothing to call. Add the method without the else and nothing ever calls it. That's why this survives casual inspection: each half looks like an oversight you could shrug at, and only together do they explain the silence.

The net effect is that WiFiClientSecure sits in certificate-verification mode with no CA bundle loaded, so every WSS connection fails verification — and fails in a way that surfaces as nothing at all.

Both bugs are still present in v0.5.4 and on master. The last upstream commit was June 2024. Bumping the version will not save you.

The fixes are upstream as PR #175 — six lines across two commits, mirroring what the ESP8266 path already does, and only reachable when no credentials are supplied. If you've been staring at issues #120, #101 or #152, I think this is your bug.

https://github.com/gilmaimon/ArduinoWebsockets/pull/175

VA5 vendors a patched copy in src/, which is part of why the project is GPL-3.0 — the library is GPL-3.0, the change notices are in the modified files, and VENDORED.md records what was altered and why. If you'd rather patch your own copy, the two hunks above are the whole functional change.

Two things to know if you vendor it yourself. The internal #include <tiny_websockets/...> angle-bracket includes need converting to relative "..." paths so the copy is self-contained. And if you delete the non-ESP32 platform directories, you must also trim the platform dispatch in ws_common.hpp to match — its ESP8266 and Teensy41 branches include headers from the directories you just removed, so skipping that step gives you a copy that doesn't compile.

Full source: https://github.com/iollama/Voice-Assistant-5

Discussions