AiMonitor stores monitoring images in cacheDir/monitor_images on the Android device. The system may clear this cache; when an image referenced by a tile no longer exists, the UI displays the default placeholder.
The current release supports Android 9 (API 28) and later. See the changelog for release history.
The built-in service uses a bounded request queue and processes image uploads one at a time. Image downloads are streamed, while the UI decodes images from disk at the size of their grid tiles to avoid memory spikes from multiple large images.
After the app is opened for the first time, the receiver continues running in the background as a foreground service. A persistent notification indicates that it is active. Removing the app from Recents stops the service; it starts again the next time the app is opened.
To use the device as an always-on monitoring display, enable Prevent auto-lock under Settings → Display. This option is disabled by default and keeps the screen awake only while AiMonitor is visible.
AiMonitor follows the system language by default. You can select Follow system, 中文, or English under Settings → Language.
For complete endpoint, field, response, error-code, and request-flow details, see the HTTP API documentation.
When the app starts, it probes ports beginning at 10241 and starts the HTTP service on the first available port, avoiding conflicts with a fixed port. The selected port appears on the Settings screen and is advertised on the local network through the _aimonitor._tcp. mDNS/DNS-SD service. Clients with Bonjour or NSD support can discover the device address and port without manual IP configuration.
Clients that do not support mDNS, or that operate on networks where multicast is restricted, can send the following UTF-8 text to UDP port 8080 at the network broadcast address:
AIMONITOR_DISCOVER_V1
The device replies by unicast to the source IP address and port:
{"id":"...","name":"...","port":10241,"apiVersion":"3"}Discovery records include the id, name, apiVersion, and path TXT attributes. After resolving the service, request:
GET /api/deviceThe response contains the stable device ID, user-configured device name, device model, app version, and API capabilities. The device name can be changed on the app's Settings screen.
Upload a JPG, PNG, or GIF file with a maximum request size of 8 MiB:
curl -F "file=@avatar.png" http://DEVICE_IP:HTTP_PORT/api/imagesThe original filename is replaced with a UUID filename in the response:
{"filename":"7604efdb-28c8-4aa2-b8b1-d95762cc396f.png"}Scan the cache with pagination and return image metadata only—50 items by default and up to 100, without encoding image contents in the list:
GET /api/images?offset=0&limit=50View or delete an original image directly:
GET /api/images/{filename}
DELETE /api/images/{filename}The grid update endpoint's image field accepts the filename returned by the upload endpoint. Base64 image data is not accepted:
{
"clientId": "persistent-unique-controller-id",
"username": "Alex",
"aiName": "Codex",
"content": "Running normally",
"image": "7604efdb-28c8-4aa2-b8b1-d95762cc396f.png"
}The controller must also call POST /api/clients/{clientId}/heartbeat every 30 seconds. If no heartbeat is received for two consecutive minutes, the device automatically clears every grid tile owned by that controller.
This project is licensed under the PolyForm Noncommercial License 1.0.0. You may use, modify, and distribute the source code for noncommercial purposes, but commercial use is prohibited.
Because commercial use is restricted, this project is source-available software rather than open-source software under the OSI definition.

