The client helpers in this folder are the "batteries included" networking layer
for smallOS.
They are all built on the same cooperative transport model:
- one thread
- no
asyncioevent loop ownership - sockets suspended and resumed by the smallOS scheduler
- the same kernel surface used on Unix today and targeted for MicroPython
If you already know the runtime and just want protocol-level usage, this is the best entry point.
These clients aim to be:
- easy to use from
async defsmallOS tasks - portable across desktop Python and future MicroPython kernels
- dependency-light
- explicit about transport and scheduling behavior
They do not try to be drop-in replacements for full desktop networking stacks. The tradeoff is intentional: the runtime stays simple, predictable, and under smallOS control.
All protocol helpers are built on top of SmallStream.py, which provides:
- non-blocking connect
- optional TLS handshake layered through the active kernel
- cooperative
send_all - cooperative
read_exactly - cooperative
read_until
That means every client here inherits the same benefits:
- tasks yield when a socket is not ready
- the scheduler can keep running higher-priority work
- no background threads are required
All of the clients also honor SmallOSConfig.client_defaults when they are
constructed from an attached task. That lets you set project-wide defaults for
things like stream buffer limits, HTTP response caps, Redis parser limits, and
MQTT keepalive / packet limits in one place.
File: SmallStream.py
This is the low-level byte-stream helper used internally by the higher-level
clients. You would reach for SmallStream directly when:
- you are implementing a new protocol client
- you want exact control over the wire format
- Redis / HTTP / MQTT are too high-level for your use case
Core methods:
await stream.connect()await stream.send_all(data)await stream.recv_some(size=4096)await stream.read_exactly(size)await stream.read_until(delimiter)stream.close()
TLS knobs:
use_tlsserver_hostnametls_ca_filetls_cert_filetls_key_filetls_verifymax_buffer_size
File: SmallHTTP.py
SmallHTTPClient is the easiest way to make outbound web requests from
smallOS tasks.
Current scope:
- HTTP/1.1 over TCP or TLS
GET,POST,PUT,PATCH, andDELETE- query-string building
- string, bytes, form, and JSON request bodies
- response parsing for:
Content-LengthTransfer-Encoding: chunked- connection-close bodies
Important behavior:
- one request uses one stream
- the stream is closed after the response is read
- this keeps behavior simple and portable
Typical example:
from SmallPackage import SmallHTTPClient, SmallOS, SmallTask, Unix
async def fetch_status(task):
client = SmallHTTPClient(
task,
base_url="https://example.com",
tls_ca_file="certs/ca.crt", # optional for private CAs on Unix
)
response = await client.get("/", params={"demo": True})
task.OS.print("{} {}\n".format(response.status_code, response.reason))
task.OS.print(response.text()[:120] + "\n")
return response.ok
runtime = SmallOS().setKernel(Unix())
runtime.fork([SmallTask(2, fetch_status, name="fetch_status")])
runtime.startOS()Constructor options:
base_urlhostportuse_tlsserver_hostnamedefault_headerstls_ca_filetls_cert_filetls_key_filetls_verifymax_response_sizemax_buffer_size
Common request methods:
await client.get(path="", headers=None, params=None)await client.post(path="", headers=None, params=None, data=None, json_body=None)await client.put(...)await client.patch(...)await client.delete(...)
Response object:
response.status_coderesponse.reasonresponse.headersresponse.bodyresponse.okresponse.text()response.json()
Notes:
- if you pass
json_body=..., the client setsContent-Type: application/json - if you pass mapping-style
data=..., the client sendsapplication/x-www-form-urlencoded Connection: closeis sent by default
File: SmallRedis.py
SmallRedisClient is a focused RESP client for smallOS tasks.
Current scope:
- connect
- optional
AUTH - optional
SELECT - generic command execution
- convenience helpers:
pinggetsetdeletepublishsubscribe
Typical example:
from SmallPackage import SmallRedisClient
async def redis_job(task):
client = SmallRedisClient(
task,
host="127.0.0.1",
port=6379,
password="testpassword", # optional
use_tls=True, # optional
server_hostname="localhost", # optional
tls_ca_file="certs/ca.crt", # optional for private CAs on Unix
)
await client.connect()
await client.set("smallos:key", "hello")
value = await client.get("smallos:key")
client.close()
return valueUseful methods:
await client.connect()await client.command(*parts)await client.ping(message=None)await client.get(key)await client.set(key, value)await client.delete(*keys)await client.publish(channel, message)await client.subscribe(*channels)await client.read_pubsub_event()client.close()
Constructor tuning:
max_response_sizemax_nesting_depthmax_buffer_size
File: SmallMQTT.py
SmallMQTTClient is a smallOS-native MQTT 3.1.1 client aimed at common device
and hobbyist messaging workflows.
Current scope:
- connect / disconnect
- username/password auth
- TLS transport
- publish QoS 0 / 1 / 2
- subscribe QoS 0 / 1 / 2
- inbound message receive with the required ack flows
Typical example:
from SmallPackage import SmallMQTTClient
async def mqtt_job(task):
client = SmallMQTTClient(
task,
host="127.0.0.1",
port=1883,
client_id="smallos-demo",
username="smallos", # optional
password="testpassword", # optional
use_tls=True, # optional
server_hostname="localhost", # optional
tls_ca_file="certs/ca.crt", # optional for private CAs on Unix
)
await client.connect()
await client.subscribe("smallos/demo", qos=1)
await client.publish("smallos/demo", "hello from smallOS", qos=1)
message = await client.receive_message()
await client.disconnect()
return messageUseful methods:
await client.connect()await client.disconnect()await client.ping()await client.publish(topic, payload, qos=0, retain=False)await client.subscribe(topic, qos=0)await client.receive_message()
Constructor tuning:
keepalivemax_packet_sizemax_queued_messagesmax_buffer_size
File: SmallHTTP.py
SmallSSEClient keeps a cooperative text/event-stream connection open and
parses SSE events without threads.
Current scope:
- long-lived HTTP GET stream connection
id,event,data, andretrySSE fields- per-event size caps and per-line size caps
Typical example:
from SmallPackage import SmallSSEClient
async def sse_job(task):
client = SmallSSEClient(task, base_url="http://127.0.0.1:9000")
await client.connect("/events", params={"topic": "smallos"})
event = await client.read_event()
client.close()
return eventUseful methods:
await client.connect(path="", headers=None, params=None, last_event_id=None)await client.read_event()client.close()
Constructor tuning:
max_event_sizemax_line_sizemax_buffer_size
File: SmallWebSocket.py
SmallWebSocketClient provides cooperative WebSocket messaging on top of
SmallStream.
Current scope:
- ws/wss handshake (RFC 6455, version 13)
- text and binary sends
- receive text/binary messages with fragmentation support
- automatic pong replies to server ping frames
- close/disconnect helpers
Typical example:
from SmallPackage import SmallWebSocketClient
async def ws_job(task):
client = SmallWebSocketClient(task, base_url="ws://127.0.0.1:9001")
await client.connect("/chat")
await client.send_text("hello")
message = await client.receive()
await client.disconnect()
return messageUseful methods:
await client.connect(path=None, params=None, headers=None, subprotocols=None, origin=None)await client.send_text(text)await client.send_binary(data)await client.ping(payload=b"")await client.receive()await client.disconnect(code=1000, reason="")client.close()
Constructor tuning:
max_frame_sizemax_message_sizemax_line_sizemax_buffer_size
All current client helpers share the same transport-level TLS pattern.
Common TLS-related options:
use_tls=Trueserver_hostname="localhost"tls_ca_file="path/to/ca.crt"tls_cert_file="path/to/client.crt"tls_key_file="path/to/client.key"tls_verify=Falsefor controlled local testing only
Current behavior:
- Unix supports custom CA paths through the Python
sslcontext - client certificate and key paths are accepted at the transport layer
- MicroPython ports vary more by TLS implementation, so availability may differ
Current auth support by client:
- HTTP: protocol-level auth headers are left to the caller
- Redis: username/password via
AUTH - MQTT: username/password in
CONNECT
Use SmallHTTPClient when:
- you want easy request/response web calls
- you do not want to handcraft sockets and request lines
Use SmallRedisClient when:
- you want a lightweight Redis integration inside the smallOS scheduler
Use SmallMQTTClient when:
- you want broker messaging without threads or
asyncio
Use SmallSSEClient when:
- you want long-lived server push over HTTP event streams
Use SmallWebSocketClient when:
- you want bidirectional low-latency messaging over one socket
Use SmallStream when:
- you are implementing your own protocol
- you need exact byte-level control
The repository includes unit coverage for the protocol helpers in: tests/test_protocol_clients.py
There is also a local-only integration compose setup under .local/ that can
be used to bring up Redis and Mosquitto for live manual testing on desktop
Python without committing those test fixtures to git.