Limits¶
Every cap AWTRIX enforces, and what it answers when you reach one.
Requests¶
| Limit | Value | At the edge |
|---|---|---|
| JSON request body (HTTP) | 8192 bytes | 413 payloadTooLarge, nothing is applied |
| MQTT command payload | 8192 bytes | dropped before it is parsed: no error, no /result reply |
| App and script names | 1–32 characters of A–Z, a–z, 0–9, _, - |
400 invalidName |
The byte-count cap is not the only limit: nested objects and arrays may go at most 16 levels
deep. Deeper nesting makes the body invalid JSON (400 invalidJson). There is still no cap on the
number of members at a given level.
What AWTRIX publishes to you over MQTT has no size limit; only what you publish to it does.
Apps and notifications¶
| Limit | Value | At the edge |
|---|---|---|
| Pushed apps resident | 50 | 507 insufficientStorage, nothing is stored - delete an app first |
| Notification queue | 32, counting the one on screen | a stacked push is rejected with 507 insufficientStorage; stack: false replaces the notification on screen and is never rejected |
| Notifications per request | 1 | 422 validationFailed - send one per request |
barChart / lineChart points |
16 | the 17th and later entries are dropped, the chart still draws |
Additional positioned icons (icons) |
4 per pushed app or notification, plus the ordinary icon |
422 validationFailed on icons; the whole request is rejected |
The 50 counts new names only: replacing a pushed app that already exists always works, whatever
the count says. An array payload is all-or-nothing against the cap - if the new names in the batch
would take the total past 50, the whole request is rejected with 507 and none of its apps are
created or updated.
Scripting¶
Berry scripts run under their own caps. How each one behaves in practice is in App scripting.
| Limit | Value | At the edge |
|---|---|---|
| Instructions per entry | 200 000 | the script stops and stays broken until you replace it; nothing else is affected |
| Shared script memory | 96 KB on a board without PSRAM; half the free PSRAM on a board with it | new installs refused until it drops; nothing already installed is removed |
| Free memory to install | about 8 KB plus the source; re-saving an existing script, about 4 KB plus the source | install refused, 507 - what helps |
| Memory in one piece | at least the size of the source | install refused, 507, "heap too fragmented to compile" - reboot |
| Memory held back while a script compiles | 24 KB, on a board without PSRAM | install fails with out of memory |
| HTTP response body | 8 KB, or cap if the request sets one - brought down to the free memory there is when the answer starts arriving |
truncated at whichever of the two is smaller - or filtered, see find |
| Free memory while a response is collected | enough for the bytes still to come | the whole request fails: the callback gets nil and the real status code |
| HTTP connect and read timeout | 5 s each | the callback gets nil, 0 |
| HTTP request unanswered | 30 s | the callback gets nil, 0, the slot is freed |
| HTTP requests in flight | 8 per script | http.get() calls back nil, 0 immediately |
| Script timers | 8 per app, 32 in total; 25 ms to 1 day | timer.after() and timer.every() return nil when full or invalid |
| MQTT subscriptions | 8 per script | further mqtt.subscribe() calls are ignored |
| MQTT messages waiting | 32, shared by every script | the oldest pending message is dropped |
| Setting key | 1–24 characters of A–Z, a–z, 0–9, _, starting with a letter |
the line is skipped and the settings panel says so |
| Setting text value | 256 characters, or maxlen= if you set one |
the change is refused, 422, nothing is written |
| Shared key names | 1–24 characters of A–Z, a–z, 0–9, _, - |
shared.set() returns false, nothing changes |
| Music bands | 32 | music.bands(n) answers at most 32 values; a smaller n merges neighbours |
| Different script icons per frame | 4 icon IDs | icon() returns false for a 5th distinct ID in the same draw() |
Using the same script icon ID at several positions counts as one icon. Those copies animate together.
The instruction limit is per entry into script code - one draw(), one loop(), one button
press, one HTTP callback each get the full 200 000 again, and it is not a limit a try/except
can catch.
Sounds and radio¶
| Limit | Value | At the edge |
|---|---|---|
| Melody source | 512 characters | 422 validationFailed |
| Melody name | 1–24 characters of A–Z, a–z, 0–9, _, - |
422 validationFailed |
| MP3 name | 1–32 characters of A–Z, a–z, 0–9, _, - |
refused at upload |
| DFPlayer track | 1–2999 | 422 validationFailed |
| Radio stations | 32 | 422 validationFailed, the whole list is rejected |
| Station name | 1–24 characters | 422 validationFailed, naming the row that failed |
| Station URL | at most 255 characters, http:// or https:// |
422 validationFailed, naming the row that failed |
A station list is applied whole or not at all: one bad row rejects the request and the stations already on AWTRIX stay as they were.
Storage¶
| Limit | Value | At the edge |
|---|---|---|
| Icon and file storage | the free space on AWTRIX - the storage area is 512 KB on a 4 MB board, 4.5 MB on 8 MB, 12.5 MB on 16 MB | 500 internalError; no truncated file is left behind |
Which formats are accepted, and how each one is drawn, is in Icons & assets.
Display¶
| Limit | Value | At the edge |
|---|---|---|
| Panel width | panelWidth × panels, default 32 × 1, must come to 32–128 |
outside the range: 422 validationFailed on panelWidth |
| Panel height | 8 pixels | fixed; not configurable |
| GIF dimensions | up to the panel's width and height | resize larger GIFs before uploading; every animation frame must fit |
What is not limited¶
- Requests per second. Neither the HTTP API nor MQTT rate-limits you.
- State AWTRIX publishes.
state/deviceandstate/screengo out at whatever size they are. - How long a script may run in total. Only a single entry into script code is capped; a script that returns promptly may run for as long as AWTRIX is on.