All endpoints are served on port 80. JSON is used for all request and response bodies unless noted otherwise.
| Item | Value |
|---|---|
| Base URL | http://<device-ip> |
| Content-Type | application/json |
| Authentication | None |
| CORS | * (all origins) |
Endpoints used by NM Monitor for LAN device discovery and live status polling.
Lightweight identity probe. Called by NM Monitor on every reachable LAN host to decide whether it is a compatible miner. hr and ver must both be present; if either is missing the host is skipped.
Response 200
{
"model": "NMMiner",
"hostname": "NMMiner-ABCD",
"ver": "2.1.0",
"sw": 320,
"sh": 240,
"hr": 2450000000,
"sbd": 45200000000,
"ebd": 1230000000000,
"ut": 5025
}| Field | Description |
|---|---|
model |
Device type — routes NM Monitor to /api/system/info |
hostname |
mDNS / display name |
ver |
Firmware version (required for discovery) |
sw / sh |
Screen width / height in pixels |
hr |
Hashrate in H/s (required for discovery) |
sbd |
Session best difficulty (H) |
ebd |
All-time best difficulty (H) |
ut |
Uptime in seconds since last boot |
Returns the device's own IP and a deduplicated list of all reachable hosts found by the background LAN ping scan. Wakes the scan thread if sleeping.
Note The background scan thread only runs while the device is on the Miner page. Calling this endpoint wakes the scan thread and resets a 30-second idle timer. If no further
/aliverequest arrives within 30 s and the device has left the Miner page, the scan thread sleeps and subsequent responses return an emptyipslist.
Response 200
{
"self": "192.168.1.100",
"ips": [
"192.168.1.100",
"192.168.1.101",
"192.168.1.105"
]
}Full real-time snapshot: device identity, mining statistics, active stratum pool, and temperatures. Polled by NM Monitor when /probe returns model = "NMMiner".
Response 200
{
"identity": {
"hwModel": "NMMiner",
"hostName": "NMMiner-ABCD",
"fwVersion": "2.1.0",
"rssi": -62
},
"miner": {
"hashRate": 2.45,
"sAccepted": 42,
"sRejected": 0,
"uptimeSeconds": 5025,
"uptimeEver": 86400,
"networkDiff": "92.67T",
"poolDiff": "8.00K",
"lastDiff": "12.30K",
"bestDiffSession": "45.20K",
"bestDiffEver": "1.23M",
"blkhits": 0,
"freeHeap": 145408,
"minFreeHeap": 131072
},
"stratum": {
"url": "solobtc.nmminer.com:3333",
"user": "18dK8EfyepKuS74fs27iuDJWoGUT4rPto1.worker"
},
"temps": {
"vcore": 42.5,
"asic": null
},
"storage": {
"fsTotal": 393216,
"fsUsed": 262144
}
}| Field | Description |
|---|---|
identity.rssi |
Wi-Fi signal strength in dBm |
miner.hashRate |
Current hashrate in GH/s |
miner.uptimeSeconds |
Seconds since last boot |
miner.uptimeEver |
Cumulative seconds (NVS + session) |
temps.vcore |
Core temperature in °C; null if sensor absent |
storage.fsTotal / fsUsed |
LittleFS total / used bytes |
All settings endpoints support partial updates — include only the keys you want to change. Changes are persisted to NVS flash. The Wi-Fi password is never returned in GET responses.
Read or update hostname and Wi-Fi credentials.
Note Only include the Wi-Fi password when you actually want to change it. Credential changes require a reboot to reconnect.
GET Response 200
{
"Hostname": "NMMiner-ABCD",
"WiFiSSID": "MyNetwork"
}POST Request Body (all keys optional)
{
"Hostname": "NMMiner-NEW",
"WiFiSSID": "MyNetwork",
"WiFiPWD": "newpassword"
}POST Response 200 — OK (text/plain)
Read or update stratum pool configuration. New pool connection takes effect after reboot.
GET Response 200
{
"PrimaryPool": "stratum+tcp://solobtc.nmminer.com:3333",
"PrimaryAddress": "18dK8EfyepKuS74fs27iuDJWoGUT4rPto1.worker",
"PrimaryPassword": "x",
"SecondaryPool": "stratum+tcp://au.solobtc.nmminer.com:3333",
"SecondaryAddress": "18dK8EfyepKuS74fs27iuDJWoGUT4rPto1.worker",
"SecondaryPassword": "x"
}POST Request Body (all keys optional)
{
"PrimaryPool": "stratum+tcp://solobtc.nmminer.com:3333",
"PrimaryAddress": "yourWallet.worker",
"PrimaryPassword": "x",
"SecondaryPool": "stratum+tcp://au.solobtc.nmminer.com:3333",
"SecondaryAddress": "yourWallet.worker",
"SecondaryPassword": "x"
}POST Response 200 — OK (text/plain)
Read or update time and date settings. Timezone, TimeFormat, and DateFormat all take effect immediately on the device display without a reboot.
GET Response 200
{
"Timezone": "8",
"TimeFormat": 24,
"DateFormat": "YYYY-MM-DD"
}| Field | Values |
|---|---|
Timezone |
UTC offset as numeric string (e.g. "8" = UTC+8, "-5" = UTC-5) |
TimeFormat |
12 or 24 |
DateFormat |
"YYYY-MM-DD" | "MM/DD/YYYY" | "DD/MM/YYYY" |
POST Request Body (all keys optional)
{
"Timezone": "-5",
"TimeFormat": 12,
"DateFormat": "MM/DD/YYYY"
}POST Response 200 — OK (text/plain)
Read or update display and LED preferences. Brightness, RotateScreen, ScreenSaver, and ScreenSaverMode take effect immediately. LedEnable requires a reboot.
GET Response 200
{
"Brightness": 80,
"RotateScreen": 270,
"LedEnable": 1,
"ScreenSaver": "never",
"ScreenSaverMode": "image"
}| Field | Values |
|---|---|
Brightness |
1 – 100 |
RotateScreen |
0 | 90 | 180 | 270 |
LedEnable |
0 = off, 1 = on |
ScreenSaver |
"never" | "30s" | "1m" | "5m" | "15m" | "30m" |
ScreenSaverMode |
"image" | "black" |
POST Request Body (all keys optional)
{
"Brightness": 60,
"RotateScreen": 90,
"LedEnable": 0,
"ScreenSaver": "5m",
"ScreenSaverMode": "black"
}POST Response 200 — OK (text/plain)
Read or update market display settings. After saving, the market task triggers an immediate data refresh — no reboot required. WatchCoins is silently truncated to 20 symbols.
GET Response 200
{
"MainCoin": "BTC",
"WatchCoins": "ETH,BNB,SOL",
"KlineRotate": "20s",
"KlineInterval": "1h",
"PricePageMode": "kline"
}| Field | Values |
|---|---|
MainCoin |
Primary coin shown on price page |
WatchCoins |
Comma-separated watchlist (max 20 symbols) |
KlineRotate |
"never" | "10s" | "20s" | "60s" | "5m" | "30m" |
KlineInterval |
"1m" | "5m" | "15m" | "30m" | "1h" | "4h" | "1d" | "1w" |
PricePageMode |
"kline" | "pricewall" |
POST Request Body (all keys optional)
{
"MainCoin": "ETH",
"WatchCoins": "BTC,BNB,SOL,XRP",
"KlineRotate": "60s",
"KlineInterval": "15m",
"PricePageMode": "pricewall"
}POST Response 200 — OK (text/plain)
Read or update weather location. After saving, the weather task triggers an immediate data fetch — no reboot required.
GET Response 200
{
"WeatherCity": "Beijing, Beijing, China",
"WeatherLat": "39.9075",
"WeatherLon": "116.3972",
"WeatherTempUnit": "celsius",
"WeatherSpeedUnit": "kmh",
"WeatherAltMode": "pressure"
}| Field | Values |
|---|---|
WeatherTempUnit |
"celsius" | "fahrenheit" |
WeatherSpeedUnit |
"kmh" | "mph" | "ms" | "kn" |
WeatherAltMode |
"pressure" | "altitude" |
POST Request Body (all keys optional)
{
"WeatherCity": "Tokyo, Tokyo, Japan",
"WeatherLat": "35.6762",
"WeatherLon": "139.6503",
"WeatherTempUnit": "fahrenheit",
"WeatherSpeedUnit": "mph",
"WeatherAltMode": "altitude"
}POST Response 200 — OK (text/plain)
Read-only market data cached on the device from Binance.
Returns a cached list of USDT trading pair base symbols fetched from Binance. Used by the settings page to populate coin selection dropdowns. The list may be empty shortly after first boot.
Note The market data thread only runs while the device is on the Miner, Clock, or Price page. If the device is on the Loading, Config, or Weather page, the market thread is asleep and this endpoint returns an empty array
[].
Response 200
["BTC", "ETH", "BNB", "SOL", "XRP", "DOGE", "ADA", "TRX", ...]Triggers an immediate weather + AQI fetch, bypassing the normal polling interval. Rate-limited to once per 60 seconds.
Request Body
{}Response 200 — OK (text/plain)
Response 429 — Rate limited, please wait 42s before refreshing again. (text/plain)
Triggers a brief visual alert (screen flash / LED blink) on the physical device to help identify it among multiple units on the same network.
Request Body
{}Response 200
{ "status": "ok" }Triggers an immediate software reboot. The HTTP 200 response is delivered before the reboot sequence starts (~600 ms delay).
Warning The device will be unreachable for several seconds while rebooting.
Request Body
{}Response 200
{ "status": "ok" }Upload custom screensaver images to the device. Files must be in the NMMiner .ss binary format (RGB565 + RLE/Huffman compression). Each file is named saver_{W}_{H}_{NNN}.ss where W×H matches the device screen resolution.
Call before uploading a .ss file to check available space or whether older files must be removed.
Query Parameters
| Parameter | Required | Description |
|---|---|---|
size |
✓ | File size in bytes |
Response 200
{
"fileSize": 81920,
"fsFree": 118784,
"maxUploadable": 204800,
"action": "new",
"overwriteCount": 0,
"overwriteFiles": [],
"existingCount": 2,
"spaceAfter": 36864
}action |
Meaning |
|---|---|
"new" |
Enough free space for the new file |
"overwrite" |
Old files must be deleted to make room |
"reject" |
Not enough space even after deleting old files |
Error Responses
400— Missingsizeparameter400— Invalidsizevalue
Upload a .ss binary file via multipart/form-data. The firmware validates the file header (magic 0x4E53) in the first chunk and rejects invalid files immediately. If free space is insufficient, the oldest matching screensaver file(s) are automatically deleted to make room.
Warning Maximum file size is 200 KB. Files exceeding this limit are rejected with HTTP 413.
Request
Content-Type: multipart/form-data
file: <binary .ss data> // field name: any (filename must end in .ss)
Response 200
{
"status": "ok",
"path": "/ss/saver_320_240_003.ss"
}Error Responses
400— Only.ssfiles are accepted400— Invalid.ssfile header413— File too large (max 200 KB)500— Failed to open file for writing500— Write error