# 25.WebSocketClient - the device connects to a WebSocket server

**Layer:** L7 Application · **Build flags:** `DETWS_ENABLE_WS_CLIENT` (optional `DETWS_ENABLE_TLS` + `DETWS_ENABLE_WS_CLIENT_TLS` for `wss://`)

## What this example teaches

The mirror of the server-side WebSocket: here the device is the **client**. It
connects to a remote WebSocket endpoint, sends a text message once a second, and
prints whatever the server sends back (the demo points at a public echo service,
so it receives its own messages). Client frames are masked per RFC 6455; ping/pong
and close are handled by `ws_client_loop()`.

**Register the receive callback, then connect:**

```cpp
ws_client_on_message(on_message);
if (ws_client_connect(HOST, PORT, USE_TLS, PATH))   // USE_TLS -> wss://
    Serial.println("WebSocket connected");
```

**Pump and send each loop.** `ws_client_loop()` services the connection (ping/pong,
close, inbound frames); `ws_client_send_text()` sends:

```cpp
void loop() {
    ws_client_loop();
    if (ws_client_connected() && /* once a second */)
        ws_client_send_text(msg);
}
```

This demo uses a `wss://` echo so it needs the TLS flags; for a plain `ws://`
endpoint, build with only `-DDETWS_ENABLE_WS_CLIENT=1`, set `USE_TLS=false`, and
`PORT=80`.

## Build and run

```sh
pio ci --board=esp32dev --project-option="framework=arduino" \
  --project-option="build_flags=-DDETWS_ENABLE_WS_CLIENT=1 -DDETWS_ENABLE_TLS=1 -DDETWS_ENABLE_WS_CLIENT_TLS=1" \
  --lib="." examples/L7-Application/25.WebSocketClient/25.WebSocketClient.ino
```

Flash and watch Serial @ 115200: the echo server returns each message the device
sends.

## Annotated source

The complete sketch ([25.WebSocketClient.ino](25.WebSocketClient.ino)), reproduced
verbatim with added explanatory comments:

```cpp
// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
// SPDX-License-Identifier: AGPL-3.0-or-later

#define DETWS_ENABLE_WS_CLIENT 1

#include "dwserver.h"
#include "network_drivers/physical/physical.h"
#include "services/ws_client/ws_client.h"
#include <WiFi.h>

static const char *SSID = "YOUR_SSID";
static const char *PASSWORD = "YOUR_PASSWORD";

static const char *HOST = "ws.postman-echo.com"; // public WebSocket echo (wss)
static const bool USE_TLS = true;
static const uint16_t PORT = 443;
static const char *PATH = "/raw";

// Delivered for every inbound frame (opcode 1 = text, 2 = binary).
void on_message(uint8_t opcode, const uint8_t *payload, size_t len)
{
    Serial.printf("RX (op %u): %.*s\n", opcode, (int)len, (const char *)payload);
}

void setup()
{
    Serial.begin(115200);

    init_wifi_physical(SSID, PASSWORD);
    Serial.print("Connecting to WiFi");
    while (!wifi_ready())
    {
        delay(250);
        Serial.print('.');
    }
    Serial.print("\nIP: ");
    Serial.println(WiFi.localIP());
    WiFi.setSleep(false);

    ws_client_on_message(on_message);

    if (ws_client_connect(HOST, PORT, USE_TLS, PATH))
        Serial.println("WebSocket connected");
    else
        Serial.println("WebSocket connect failed");
}

void loop()
{
    ws_client_loop(); // service ping/pong, close, inbound frames

    static uint32_t last = 0;
    static uint32_t n = 0;
    if (ws_client_connected() && millis() - last >= 1000)
    {
        last = millis();
        char msg[48];
        snprintf(msg, sizeof(msg), "hello from esp32 #%lu", (unsigned long)n++);
        ws_client_send_text(msg);
    }
}
```
