NiusCam keeps camera capture separate from network policy. Your sketch decides whether to create a SoftAP or join an existing network, whether Wi-Fi sleep is enabled, and who may connect. The optional streaming modules transport the camera's JPEG bytes without re-encoding them.
| Requirement | HTTP snapshot | HTTP MJPEG | UDP v1 |
|---|---|---|---|
| View in an ordinary browser | Yes | Yes | No, receiver required |
| One image per request | Yes | No | No |
| Continuous video | No | Yes | Yes |
| Reliable ordered delivery | TCP | TCP | No |
| Incomplete-frame policy | Request fails | TCP stream ends/fails | Receiver drops incomplete frame |
| Complete-frame CRC | No | No | Yes |
| Lowest measured local-link latency | No | Moderate | Best of the verified transports |
Start with HTTP for usability. Choose UDP when the receiver is controlled by the project and frame freshness matters more than guaranteed delivery.
All NiusCam streaming paths require PixelFormat::Jpeg:
Config config;
config.useTurbo();
config.pixelFormat = PixelFormat::Jpeg;
Result result = camera.begin(config);NiusCam sends the sensor-produced JPEG. It does not spend CPU, memory, or quality on a second encode.
The bundled examples create a local access point so users do not put private Wi-Fi credentials into a library example:
#include <WiFi.h>
WiFi.mode(WIFI_AP);
WiFi.setSleep(false);
if (!WiFi.softAP("NiusCam", "niuscam-demo")) {
Serial.println("SoftAP failed");
return;
}
Serial.println(WiFi.softAPIP());The example password is public and intended only for a local demonstration. Use a project-specific credential and appropriate network isolation in a real deployment.
Disabling Wi-Fi sleep favors responsiveness and increases power consumption. Applications may choose another policy and measure its latency/power tradeoff.
NiusCam does not call WiFi.begin() for you:
WiFi.mode(WIFI_STA);
WiFi.begin(networkName, networkPassword);
uint32_t started = millis();
while (WiFi.status() != WL_CONNECTED && millis() - started < 15000)
delay(100);
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Wi-Fi connection timed out");
return;
}Keep credentials in a private project file or provisioning system, not in a published sketch.
#include <NiusCamHttp.h>
HttpStreamServer server;
Result result = server.begin(camera, 80);
if (!result) {
Serial.print("HTTP startup failed: ");
Serial.println(result.message());
}| Route | Response |
|---|---|
/ |
Minimal responsive viewer page |
/snapshot.jpg |
One newly captured JPEG with no-store caching |
/stream |
Continuous multipart/x-mixed-replace MJPEG stream |
For a SoftAP with the normal default address, open:
http://192.168.4.1/
Always print WiFi.softAPIP() or WiFi.localIP() rather than assuming the
address in application UI.
The MJPEG handler enables TCP no-delay to reduce buffering latency. It captures in the HTTP server task while the stream client remains connected.
Do not call camera.capture(), reconfigure(), recover(), suspend(), or
end() from another task while an MJPEG client is streaming. Stop the server or
provide application-level locking and a single capture owner.
#include <NiusCamUdp.h>
UdpFrameSender sender;
IPAddress receiver(192, 168, 4, 2);
Result result = sender.begin(receiver);
Frame frame = camera.capture();
if (frame)
result = sender.send(frame);begin() parameters are:
sender.begin(destination,
destinationPort, // Default 5005
localPort, // Default 0: choose an ephemeral port
packetIntervalUs);// Default 0: no added pacingEach JPEG is divided into payloads of at most 1200 bytes. Every packet carries frame ID, timestamp, complete size, complete-frame CRC32, chunk index/count, and payload size. A datagram enqueue is retried up to five times with short backoff when the transmit queue is busy.
The sender does not retransmit packets after network loss, adapt bitrate, or provide authentication/encryption. See UDP protocol v1.
A correct UDP receiver must:
- Identify a stream by sender address and frame ID.
- Validate magic, version, header size, bounds, and consistent metadata.
- Store each chunk at
chunkIndex * 1200. - Ignore duplicates without double-counting them.
- Complete a frame only after every chunk arrives.
- Verify the complete-frame CRC32.
- Decode/display only complete, valid JPEGs.
- Expire incomplete old frames with bounded memory.
Never display a partial JPEG merely because a final-chunk flag arrived.
Tune in this order:
- Use JPEG and begin at VGA.
- Confirm stable camera-only capture.
- Measure the real average and worst-case JPEG size.
- Select Balanced or Turbo based on frame freshness.
- Keep the receiver and board on a clean, nearby link for baseline tests.
- Adjust JPEG quality and resolution to fit available airtime.
- Add a small UDP packet interval only if queue contention or local loss improves with pacing.
- Test disconnect/reconnect behavior and long-running heap stability.
Lower JPEG quality numbers create larger frames and more packets. High sensor gain can also enlarge JPEGs by introducing noise.
- HTTP clients can reconnect by opening the route again.
- A disconnected MJPEG client ends its handler; the server remains active.
- UDP has no connection state. The sender reports only local send/queue errors, not whether a remote receiver displayed the frame.
- A receiver should treat a new frame ID as permission to discard stale, incomplete work according to its memory/latency policy.
The measured comparison and test scope are in Verified results.
The built-in transports provide no application authentication, access-control UI, TLS termination, or UDP encryption. SoftAP WPA protects only the wireless link and a demonstration password is not a deployment secret. For an exposed or untrusted network, add a controlled gateway, VPN, authenticated application protocol, or another security layer appropriate to the product.