{"id":30113656,"url":"https://github.com/nmattia/uht","last_synced_at":"2026-02-15T17:29:56.879Z","repository":{"id":308618830,"uuid":"1033408511","full_name":"nmattia/uht","owner":"nmattia","description":"micro HTTP toolkit for MicroPython and CircuitPython","archived":false,"fork":false,"pushed_at":"2026-02-14T12:24:38.000Z","size":49,"stargazers_count":14,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-14T20:03:50.569Z","etag":null,"topics":["embedded","esp32","http","micropython","python","raspberry-pi-pico"],"latest_commit_sha":null,"homepage":"https://nmattia.github.io/uht/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nmattia.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-08-06T19:11:21.000Z","updated_at":"2026-02-14T12:24:42.000Z","dependencies_parsed_at":"2025-08-06T23:44:18.481Z","dependency_job_id":null,"html_url":"https://github.com/nmattia/uht","commit_stats":null,"previous_names":["nmattia/uht"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/nmattia/uht","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nmattia%2Fuht","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nmattia%2Fuht/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nmattia%2Fuht/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nmattia%2Fuht/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nmattia","download_url":"https://codeload.github.com/nmattia/uht/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nmattia%2Fuht/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29485960,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-15T15:33:17.885Z","status":"ssl_error","status_checked_at":"2026-02-15T15:32:53.698Z","response_time":118,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["embedded","esp32","http","micropython","python","raspberry-pi-pico"],"created_at":"2025-08-10T07:26:50.079Z","updated_at":"2026-02-15T17:29:56.873Z","avatar_url":"https://github.com/nmattia.png","language":"Python","readme":"# uht - micro HTTP Toolkit\n\nA minimal, fully async HTTP/1.0 server for tiny devices (ESP32, Raspberry Pi Pico, etc.) running [MicroPython](https://github.com/micropython/micropython) or [CircuitPython](https://github.com/adafruit/circuitpython). Compatible with MicroPython 1.21+.\n\n```python\nfrom uht import HTTPServer\n\napp = HTTPServer()\n\n@app.route(\"/hello/\u003cname\u003e\")\nasync def greet(req, resp, name):\n    await resp.send(f\"Hello, {name}!\")\n\napp.run()\n```\n\nThe [Basic Usage](#basic-usage) section shows how to quickly get started. The [Installation Instructions](#installation-instructions) section shows advanced installation options. The [Examples](#examples) section shows real-world examples. There is also an [API reference page](https://nmattia.github.io/uht/).\n\n## Basic Usage\n\nThis shows the 3 steps to get an app running on a board, assuming you have [`mpremote`](#installing-mpremote) installed.\n\nMake sure your board is connected via USB and install `uht` with `mip`:\n\n```bash\nmpremote mip install logging\nmpremote mip install \"https://github.com/nmattia/uht/releases/latest/download/uht.py\"\n```\n\nCreate a file named `main.py` with the following content:\n\n```python\nimport network\nfrom uht import HTTPServer\n\nnic = network.WLAN(network.AP_IF)\nnic.active(True)\nnic.config(ssid=\"uht-test-server\", security=network.WLAN.SEC_OPEN)\n\n(ip, _, _, _) = nic.ifconfig()\n\nprint(f\"URL: 'http://{ip}'\")\n\napp = HTTPServer()\n\n@app.route(\"/\")\nasync def index(req, resp):\n    await resp.send(b\"Hello, world!\")\n\napp.run()\n```\n\nRun the server on the device:\n\n```shell\nmpremote run main.py\n```\n\nThe server is now running. Connect to WiFi network `uht-test-server` and visit `http://192.168.4.1/`.\n\n## Installation instructions\n\nThis assumes MicroPython was already flashed to your board.\n\n### Installing with mpremote\n\nThis uses `mpremote`. This does not require the board to be connected to the internet.\n\nInstall the library and dependencies:\n\n```shell\nmpremote mip install logging\nmpremote mip install \"https://github.com/nmattia/uht/releases/latest/download/uht.py\"\n```\n\nIf resource constrained or if you don't plan on tweaking the code install the `.mpy` module:\n\n```\nmpremote mip install \"https://github.com/nmattia/uht/releases/latest/download/uht.mpy\"\n```\n\n\nhttps://docs.micropython.org/en/latest/reference/mpremote.html\n\n### Installing from MicroPython REPL\n\nUse MicroPython's built-in package manager `mip` to install the `logging` library (dependency of `uht`) and `uht`. This requires the board to be connected to the internet.\n\n```python\nimport mip\nmip.install(\"logging\")\nmip.install(\"https://github.com/nmattia/uht/releases/latest/download/uht.py\")\n```\n\n\n## Examples\n\nThese examples use `mpremote`. See instructions on how to install it or adapt to your IDE.\n\nThe first two examples show how to set up networking. The other examples assume working networking.\n\n### Full Hello World in AP mode\n\n_The devices creates a new WiFi network (i.e. Access Point mode) and serves \"Hello, World!\". The device won't have access to the internet and you will need to connect to it directly._\n\nCreate a file `main_ap.py` with the following:\n\n```python\nimport network\nfrom uht import HTTPServer\n\nnic = network.WLAN(network.AP_IF)\nnic.active(True)\nnic.config(ssid=\"uht-test-server\", security=network.WLAN.SEC_OPEN)\n\n(ip, _, _, _) = nic.ifconfig()\n\nprint(f\"URL: 'http://{ip}'\")\n\napp = HTTPServer()\n\n@app.route(\"/\")\nasync def index(req, resp):\n    await resp.send(b\"Hello, world!\")\n\napp.run()\n```\n\nRun the server on the device:\n\n```shell\nmpremote run main_ap.py\n```\n\n### Full Hello World in STA mode\n\n_The devices connects to a known WiFi network and serves \"Hello, World!\"._\n\nCreate a file `main_sta.py` with the following:\n\n```shell\n$ mpremote edit :/config.json\n{  \"SSID\": \"my-ssid\",\n    \"PK\": \"wpa-password\"\n}\n```\n\nWrite this to `main_sta.py`:\n\n```python\nimport io\nimport time\nimport json\nimport network\nfrom uht import HTTPServer\n\ndef read_config():\n    with io.open(\"config.json\", \"r\") as f:\n        return json.load(f)\n\n\n# enable station interface and connect to WiFi access point\nnic = network.WLAN(network.WLAN.IF_STA)\nnic.active(True)\ncfg = read_config()\nnic.connect(cfg[\"SSID\"], cfg[\"PK\"])\n\nwhile not nic.isconnected():\n    print(\"waiting for connect\")\n    time.sleep(1)\n\n(ip, _, _, _) = nic.ifconfig()\n\nprint(f\"URL: 'http://{ip}'\")\n\napp = HTTPServer()\n\n@app.route(\"/\")\nasync def index(req, resp):\n    await resp.send(b\"Hello, world!\")\n\napp.run()\n```\n\nRun the server on the device:\n\n```shell\nmpremote run main_sta.py\n```\n\nNote the URL printed out.\n\n### Route with Parameter\n\nDefine a dynamic route that greets the user by name:\n\n```python\nfrom uht import HTTPServer\n\napp = HTTPServer()\n\n@app.route(\"/hello/\u003cname\u003e\")\nasync def greet(req, resp, name):\n    await resp.send(\"Hello, {name}!\")\n\napp.run()\n```\n\n### Custom Status Code and Header\n\nCustom HTTP status codes and additional response headers can be set as follows:\n\n```python\nfrom uht import HTTPServer\n\napp = HTTPServer()\n\n@app.route(\"/custom\")\nasync def custom_response(req, resp):\n    resp.set_status_code(202)\n    resp.set_reason_phrase(\"Accepted\")\n    resp.add_header(\"X-Custom\", \"Value\")\n    await resp.send(b\"Custom response\")\n\napp.run()\n```\n\n\u003e [!NOTE]\n\u003e\n\u003e The status code and headers must be set before the first call to `send()` otherwise an exception will be thrown!\n\nResponse:\n\n```\nHTTP/1.0 202 Accepted\nX-Custom: Value\n```\n\n### Catch-All Route\n\nA catch-all handler can be registered:\n\n```python\n@app.catchall()\nasync def not_found(req, resp):\n    resp.set_status_code(404)\n    await resp.send(b\"Custom 404 Not Found\")\n```\n\n\u003e [!NOTE]\n\u003e\n\u003e The status code and headers must be set before the first call to `send()` otherwise an exception will be thrown!\n\nAny request that doesn't match a defined route will now return:\n\n```\nHTTP/1.0 404\nCustom 404 Not Found\n```\n\n\n### Running in an Async Context\n\nIf you need to integrate the server with other async code (e.g., background tasks), use the `start()` method instead of `run()`. This approach gives you more control and allows you to schedule other coroutines alongside the HTTP server.\n\n```python\nfrom machine import Pin\nfrom uht import HTTPServer\nimport asyncio\n\napp = HTTPServer()\n\nled_gpio = 8 # GPIO pin driving an LED\n\nstate = { \"blink_interval_ms\" : 500 } # shared state\n\n@app.route(\"/fast\")\nasync def index(req, resp):\n    state['blink_interval_ms'] = 250\n\n@app.route(\"/slow\")\nasync def index(req, resp):\n    state['blink_interval_ms'] = 1000\n\nasync def blink():\n    pin = Pin(led_gpio, Pin.OUT)\n    while True:\n        pin.toggle()\n        await asyncio.sleep_ms(state['blink_interval_ms'])\n\nasync def main():\n    server = await app.start()\n    asyncio.create_task(blink())\n\n    print(\"Server started\")\n\n    await server.wait_closed()  # Finish if the server shuts down for any reason\n\nasyncio.run(main())\n```\n\n\n## About\n\nThe `uht` library started as a fork of [tinyweb](https://github.com/belyalov/tinyweb) by [Konstantin Belyalov](https://github.com/belyalov). Over time the library was pretty much completely rewritten.\n\nThe full diff (before the first commit on this repo) can be found [here](https://github.com/nmattia/tinyweb-ng/compare/7669f03cdcbb62a847e7d4917673be52ad2f7e79..e11bd40756669dc48ad34b56a4be8e6b8e6bbb9e).\n","funding_links":[],"categories":["Libraries"],"sub_categories":["Communications"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnmattia%2Fuht","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnmattia%2Fuht","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnmattia%2Fuht/lists"}