The net functions let a Lua plugin talk directly to your own server, without going through obniz Cloud. They send and receive data over the network interface that the device is currently connected through, and cover three protocols: HTTP (net.http), raw TCP (net.tcp), and UDP (net.udp).
Use them when a device needs to reach an existing API, a private endpoint, or a service that obniz Cloud does not handle.
Common Behavior and Constraints
Read this section before using any of the net functions.
- They follow the active network interface. HTTP and TCP run over whichever interface is currently connected — Wi-Fi, Ethernet, or LTE. UDP runs over Wi-Fi or Ethernet only, and is not available over LTE.
- They block until they finish. Each call runs synchronously and does not return until the operation completes, fails, or times out. The communication watchdog is fed during the wait, so a long transfer does not reset the device. The handler that called the function, however, stays blocked in the meantime. Avoid long transfers inside
on_online_loop()oron_offline_loop(), which are expected to return quickly. - Plain HTTP only — TLS is not supported. Connections are unencrypted. Use
http://URLs;https://does not work. Send sensitive data only over a network you trust. - Keep to one socket at a time. Open a single connection, finish with it, and close it before opening the next. Depending on available memory and the active network interface, a second socket may or may not succeed, so do not rely on holding several open at once. Always close a socket you no longer need.
- Errors are returned, not raised. On failure, a function returns
nilfollowed by a short error string. Check the first return value before using the result.
net.http
net.http.get(url)
Performs an HTTP GET request and waits for the full response.
| Argument | Type | Description |
|---|---|---|
url |
string | The target URL. Begins with http://. https:// is not supported. |
Returns three values on success, or nil and an error string on failure.
| Return | Type | Description |
|---|---|---|
status |
number | The HTTP status code, such as 200. |
body |
string | The response body. |
headers |
string | The raw response headers. |
net.http.post(url, body, contentType)
Performs an HTTP POST request with the given body.
| Argument | Type | Description |
|---|---|---|
url |
string | The target URL. |
body |
string | The request body to send. |
contentType |
string | Optional. The Content-Type header. Defaults to application/octet-stream. |
The return values are the same as net.http.get().
net.http.request(options)
Performs a request with full control over the method, headers, body, and timeout. options is a table.
| Field | Type | Description |
|---|---|---|
url |
string | Required. The target URL. |
method |
string | Optional. The HTTP method. Defaults to GET. |
headers |
table | Optional. Request headers, as { ["Key"] = "Value" } or { "Key: Value" }. |
body |
string | Optional. The request body. |
timeout |
number | Optional. The time to wait, in milliseconds. Defaults to 30000. |
The return values are the same as net.http.get().
HTTP constraints
The HTTP client is intentionally small, so be aware of the following limits.
- It sends
Connection: closeand reads until the server closes the connection. Keep-alive is not used. - It does not follow redirects. A
3xxresponse is returned as is. - It does not decode chunked transfer encoding or decompress
gzip. The body is returned exactly as received, so request an uncompressed, unchunked response when you can. - The host name must be shorter than 128 characters.
net.tcp
net.tcp.connect(host, port)
Opens a plain TCP connection and returns a socket id. TLS is not supported.
| Argument | Type | Description |
|---|---|---|
host |
string | The host name or IP address. |
port |
number | The port number. |
Returns the socket id on success, or nil and an error string on failure. Pass the id to the other net.tcp functions.
net.tcp.write(id, data)
Sends data over the connection. The call returns once all of the data has been sent, and times out after 30 seconds.
| Argument | Type | Description |
|---|---|---|
id |
number | The socket id from net.tcp.connect(). |
data |
string | The data to send. |
Returns the number of bytes written, or nil and an error string on failure.
net.tcp.read(id, maxlen)
Reads data that has already arrived. This call does not wait for new data.
| Argument | Type | Description |
|---|---|---|
id |
number | The socket id. |
maxlen |
number | Optional. The maximum number of bytes to read. Defaults to 1024, with an upper limit below 4096. |
| Return | Type | Description |
|---|---|---|
data |
string | nil | The received data. An empty string ("") means no data has arrived yet. nil means the connection has closed or an error occurred. |
Because read returns immediately, poll it across loop iterations rather than expecting a full message in a single call.
net.tcp.close(id)
Closes the connection and releases the socket.
net.udp
UDP runs over Wi-Fi or Ethernet only. It is not available over LTE: on a cellular connection, net.udp.open() fails with udp not supported on cellular.
net.udp.open(localPort)
Opens a UDP socket and returns its id.
| Argument | Type | Description |
|---|---|---|
localPort |
number | Optional. The local port to bind to. When omitted, the system assigns one. |
Returns the socket id on success, or nil and an error string on failure.
net.udp.sendTo(id, host, port, data)
Sends a datagram to the given destination.
| Argument | Type | Description |
|---|---|---|
id |
number | The socket id. |
host |
string | The destination host name or IP address. |
port |
number | The destination port. |
data |
string | The datagram payload. |
Returns the number of bytes sent, or nil and an error string on failure.
net.udp.receive(id, maxlen)
Receives one datagram. This call does not wait; it returns nil when no datagram is waiting.
| Argument | Type | Description |
|---|---|---|
id |
number | The socket id. |
maxlen |
number | Optional. The maximum number of bytes to read. Defaults to 1024, with an upper limit below 4096. |
| Return | Type | Description |
|---|---|---|
data |
string | nil | The received payload, or nil when nothing is waiting. |
ip |
string | The sender's IP address. |
port |
number | The sender's port. |
net.udp.close(id)
Closes the socket.
Example: Posting an Analog Reading Every Minute
The following plugin reads the voltage on IO0 once a minute and sends it directly to your own server as JSON over plain HTTP. It runs entirely on the device and does not go through obniz Cloud.
last = 0;
function on_online_loop()
-- Run once every 60 seconds
if os.getTick() - last < 60 * 1000 then
return;
end
last = os.getTick();
-- Read the analog voltage on IO0
local voltage = ad.get(0);
local body = '{"voltage":' .. tostring(voltage) .. '}';
-- POST it to your own server
local status, resp = net.http.post("http://example.com/api/measurements", body, "application/json");
if status == nil then
-- On failure, the second value holds the error string
os.log("post failed: " .. tostring(resp));
return;
end
os.log("posted, status: " .. tostring(status));
end