Networking (WiFi & HTTP)

WiFi and HTTP each live in one class: new WiFi(...) carries the whole link policy (credentials, security, timeout), and new Request(...) carries the whole request (method, URL, body, TLS policy). The same calls work three ways — blocking at the top level, fire-and-forget with callbacks, or async/await.

class

WiFi

The WiFi link. Construct the policy, then join(). The constructor carries the credentials; join() associates and waits — bounded by timeoutMs (default 15 s) — until the board has an IP address.

Example first

connect.ts
import { WiFi, UART0 } from '@typecad/hal';

const wifi = new WiFi('MyNetwork', { psk: 'correct-horse-battery-staple' });
if (wifi.join()) {
  UART0.writeLine(wifi.ip());        // the IP address as a string
}

Static IP and radio tuning

Both are construction facts, set at the same time as the credentials. With static ipv4 facts the link comes up without DHCP — join() returns as soon as the address is applied. Omit psk for an open network; security defaults to WPA2 when a psk is present and OPEN otherwise — override with the WiFi.WPA3 / WiFi.WPA2_WPA3 tokens.

static-ip.ts
const lab = new WiFi('LabNet', {
  psk: 'correct-horse-battery-staple',
  timeoutMs: 30000,                                        // 30 s deadline
  ipv4: { addr: '10.0.0.5', gateway: '10.0.0.1', netmask: '255.255.255.0' },
  powerSave: WiFi.PS_OFF,   // disable modem sleep for lower latency
  channel: 6,               // 0 / omitted = any
});

joinStart / linked joinStart(): void

Inside an async function, the join splits into a non-blocking start plus a poll, so other tasks keep running while the station associates:

async-connect.ts
const wifi = new WiFi('MyNetwork', { psk: 'hunter22' });

async function network() {
  wifi.joinStart();                       // fire-and-forget associate
  while (!wifi.linked()) { await Time.sleep(100); }
  UART0.writeLine(wifi.ip());
}

onUp / onDrop onUp(fn): void

link-events.ts
wifi.onUp(() => UART0.writeLine('online at ' + wifi.ip()));
wifi.onDrop(() => UART0.writeLine('link lost'));   // safe to call join() from here
wifi.join();

scan scan(): Scan → read-only handle, fixed pool of 16

scan.ts
const results = wifi.scan();
for (let i = 0; i < results.count(); i++) {
  UART0.writeLine(results.ssid(i) + '  ' + results.rssi(i) + ' dBm  ch' + results.channel(i));
}

All methods

MemberDescription
new WiFi(ssid, opts?)Link policy: psk, security, channel, band, timeoutMs (default 15 s), powerSave, ipv4 { addr, gateway, netmask }
join()Associate and wait for IP connectivity. Awaitable
joinStart()Fire-and-forget associate — poll linked()
leave()Disassociate
linked() / rssi() / ip() / mac()Link state and info
onUp(fn) / onDrop(fn)Link-up / link-down callbacks
scan()One blocking scan; results via the returned handle. Awaitable
class

WiFiAP

Access-point mode — bring the radio up as an AP for provisioning.

Example first

ap.ts
import { WiFiAP } from '@typecad/hal';

const ap = new WiFiAP('hal-setup', { psk: 'config123', channel: 6 });
ap.start();
// ...provisioning...
ap.stop();
class

Request

The HTTP/S client. Construction carries method, URL, timeout, body, and TLS policy; header() chains request headers; send() performs the request and leaves the response in the client until the next send.

Example first

request.ts
import { Request, UART0 } from '@typecad/hal';

const req = new Request('GET', 'http://192.168.2.184:8080/health');
req.header('X-Device', 'typecad-hal');
if (req.send()) {
  UART0.writeLine(req.status());              // 200
  UART0.writeLine(req.ok());                  // true for any 2xx
  UART0.writeLine(req.text());                // the body, until the next send
  UART0.writeLine(req.responseHeader('Content-Type'));
}

Method tokens and chaining

post.ts
new Request(Request.POST, 'http://api.local/telemetry', {
  body: '{"temp":21.5}',
  json: true,                             // sets Content-Type: application/json
  timeoutMs: 5000,
}).header('Authorization', 'Bearer x').send();

HTTPS and certificate pinning

HTTPS is native; the CA policy is a construction fact. caCert pins a specific CA (a PEM string — it's converted to binary form at build time, so no PEM parser ships on the board). insecure: true encrypts but skips verification; don't ship it in production.

https.ts
const pinned = new Request(Request.GET, 'https://internal.corp/api', { caCert: CORP_CA_PEM });
const lab    = new Request(Request.GET, 'https://lab-server.local', { insecure: true });

send (async) await req.send()

Inside an async function, await req.send() splits into send-start plus done-polling — a slow request never stalls the rest of the program:

poll-cloud.ts
async function pollCloud() {
  while (true) {
    const req = new Request(Request.GET, 'http://api.local/health');
    await req.send();
    UART0.writeLine(req.status());
    await Time.sleep(5000);
  }
}

All methods

MemberDescription
new Request(method, url, opts?)timeoutMs (default 10 s), body, json, insecure, caCert
Request.GET / POST / PUT / DELETE / HEAD / PATCHMethod tokens
header(name, value)Attach a request header; chainable
send()Perform the request. Awaitable
status() / ok() / text()Response status, 2xx check, body (until the next send)
contentLength() / responseHeader(name)Response metadata

Build-time checks

Two checks run before you flash. Using WiFi, Request, or Mqtt on a board with no WiFi radio is a build error naming an ESP32 target. And a program that issues HTTP requests without ever bringing a WiFi link up (join() or an AP) is flagged with a build-time warning — every request would fail at runtime.

© 2026 typeCAD — code-defined electronics github