Skip to content

wifi

Station-mode WiFi. Connect to an access point, observe the connection lifecycle through events, and query link status. On ESP32 the events are driven by the radio (esp_wifi); on PC a host shim reports the machine's own LAN address so programs can be developed and tested without hardware.

Version v0.1
Platform ESP32 (radio), PC (host shim)
Type Native (C)

star.mod

require dev-libs/wifi v0.1

Usage

import "wifi"

Functions

Connect / Disconnect

Function Signature Description
wifi.connect(ssid, password) (string, string) -> i32 Start async association to the AP (0=accepted, -1=error, e.g. empty ssid)
wifi.disconnect() () -> void Disconnect from the current AP
wifi.connect("MyNetwork", "secret123")

wifi.connect() is non-blocking — it returns immediately and association proceeds in the background. The connected event fires once associated, then gotip once an IP lease is obtained. Register events with wifi.on() before calling connect().

Status

Function Signature Description
wifi.isConnected() () -> bool true while associated with an AP
wifi.ip() () -> string Current IPv4 address, or empty string if not connected
wifi.rssi() () -> i32 Signal strength in dBm (0 on the host shim)
wifi.scan() () -> string Blocking all-channel scan; one SSID\|rssi\|channel line per AP found (empty on the host shim)
if (wifi.isConnected()) {
    console.log(wifi.ip())
}

wifi.scan() lists the access points the radio actually sees, one per line as SSID|rssi|channel. It is a blocking diagnostic — useful to confirm a target network is in range and to read its exact SSID bytes before calling connect(). The SSID passed to connect() must match the broadcast byte-for-byte; a common gotcha is a curly apostrophe (', U+2019) in a copied name versus the plain ' the AP actually broadcasts. On the host shim there is no radio, so it returns an empty string.

var aps: string = wifi.scan()
console.log(aps)   # e.g. "HomeNet|-48|6\nNeighbor|-80|11\n"

Auto-Reconnect

Function Signature Description
wifi.setAutoReconnect(enabled) (bool) -> void Enable/disable automatic reconnection after a drop (off by default)
wifi.setReconnectDelays(delays) (array) -> void Set the backoff delay schedule in seconds (max 8 entries)
wifi.setAutoReconnect(true)
wifi.setReconnectDelays([1, 2, 5, 10, 30])

Auto-reconnect is off by default. When enabled and the station drops:

  1. WifiDisconnected fires with the reason code
  2. After the first delay (1s), the radio re-associates
  3. If that attempt drops again, the next delay in the array is used (2s, 5s, 10s…)
  4. The last delay value repeats indefinitely until association succeeds
  5. On success, WifiConnected then WifiGotIp fire and the retry index resets to 0

If no delays are configured, a default of 1 second is used. Calling wifi.disconnect() explicitly disables auto-reconnect — only unexpected drops trigger it, never an intentional disconnect. The backoff is paced by the VM tick, so it requires runtime.keepAlive() to remain running.

Lifecycle Events

Function Signature Description
wifi.on(lifecycle, EventType) (string, i32) -> i32 Bind a lifecycle transition to a declared event type (0=success, -1=error)

Supported lifecycle strings: "connected", "gotip", "disconnected".

The event field order is fixed — declare these structs exactly as shown (field names are free, but types and order must match):

event WifiConnected {
    ssid: string
}

event WifiGotIp {
    ip: string
    netmask: string
    gateway: string
}

event WifiDisconnected {
    reason: i32
}

wifi.on("connected", WifiConnected)
wifi.on("gotip", WifiGotIp)
wifi.on("disconnected", WifiDisconnected)

on WifiGotIp fn(e: WifiGotIp): void {
    console.log("got ip " + e.ip + " gw " + e.gateway)
}

runtime.keepAlive()

The native layer emits the matching event struct when the radio transitions. The field order is verified at runtime via a signature hash — a mismatched struct is rejected. See Events.

Pattern: Connect and Report

package main

import "wifi"

event WifiConnected {
    ssid: string
}

event WifiGotIp {
    ip: string
    netmask: string
    gateway: string
}

fn main(): void {
    wifi.on("connected", WifiConnected)
    wifi.on("gotip", WifiGotIp)

    on WifiConnected fn(e: WifiConnected): void {
        console.log("connected to " + e.ssid)
    }

    on WifiGotIp fn(e: WifiGotIp): void {
        console.log("ip " + e.ip)
        runtime.exit()
    }

    wifi.connect("MyNetwork", "secret123")
    runtime.keepAlive()
}

Pattern: Credentials from Config

Keep the SSID and password out of source — read them from host-injected config:

package main

import "wifi"
import "config"

event WifiGotIp {
    ip: string
    netmask: string
    gateway: string
}

fn main(): void {
    var ssid: string = config.getString("wifi.ssid", "")
    var pass: string = config.getString("wifi.password", "")

    wifi.on("gotip", WifiGotIp)

    on WifiGotIp fn(e: WifiGotIp): void {
        console.log("online at " + e.ip)
    }

    wifi.connect(ssid, pass)
    runtime.keepAlive()
}

See config for how the host supplies wifi.ssid / wifi.password.

Pattern: Handle Auth Failure

A wrong password produces a disconnected event with a reason code. With auto-reconnect enabled, each failed association drops again and the backoff retries, so guard your own abort logic with a counter:

package main

import "wifi"

event WifiDisconnected {
    reason: i32
}

var fails: number = 0.0

fn main(): void {
    wifi.on("disconnected", WifiDisconnected)

    on WifiDisconnected fn(e: WifiDisconnected): void {
        console.log("disconnected reason ")
        console.log(e.reason)
        fails = fails + 1.0
        if (fails >= 3.0) {
            console.log("giving up")
            wifi.disconnect()  # stops the retry loop
            runtime.exit()
        }
    }

    wifi.setAutoReconnect(true)
    wifi.setReconnectDelays([1, 2, 5])
    wifi.connect("MyNetwork", "wrongpassword")
    runtime.keepAlive()
}

Notes

  • Station (STA) mode only — no SoftAP in v0.1
  • connect() is non-blocking; lifecycle is delivered as events, never as a return value
  • On ESP32, radio events fire on the system event task and are bridged to the VM task — handlers always run on the VM thread, so it is safe to call any StarLang code from them
  • Auto-reconnect is off by default; enable it with wifi.setAutoReconnect(true) and pace retries with wifi.setReconnectDelays(...) (last value repeats). An explicit wifi.disconnect() turns it off
  • The host shim has no radio: connect() reports the machine's own LAN address and fires connected + gotip synchronously, rssi() returns 0. Use it to develop event flow on PC; exercise real radio behaviour (auth failure, RSSI, reconnect) on-device
  • Single connection — one station interface per program
  • Event field order is verified at runtime via signature hash — see Events