Skip to content

API

If you are a developer and want to integrate clock configuration into your app, Home Assistant, Node-RED, scripts, or another system, use this API reference.

This document covers two independent API categories:

  • The Cloud Discovery API, hosted on a public server
  • The Device API, provided by the clock's ESP32 on the local network

These APIs use different hosts, transport protocols, response formats, and CORS policies. Do not mix them.

1. API Categories

CategoryService LocationBase URLResponse FormatCORSPrimary Use
Cloud Discovery APIPublic serverhttps://topyuan.top/clock/findapiJSON response bodyAllows any origin: *Obtain a clock's local IP address by matching its public egress IP
Device APIClock ESP32http://<clock-local-ip>Configuration data in HTTP response headers; response body is usually emptyNo CORS headersRead configuration, change settings, read ADC values, restart the device, or erase Wi-Fi credentials

Recommended call sequence: first request the Cloud Discovery API to obtain candidate localIp values, then request http://<localIp>/get or another Device API endpoint from the current local network.

If you can obtain the clock's local IP address by another method, you do not need to call the Cloud Discovery API.

2. Cloud Discovery API

2.1 General Conventions

  • Full URL: https://topyuan.top/clock/findapi
  • Service location: public server, not the clock's ESP32
  • Transport: HTTPS
  • Method: GET
  • Authentication: none
  • Successful response: 200 OK with a JSON array
  • Content type: application/json; charset=utf-8
  • CORS: Access-Control-Allow-Origin: *
  • Cache policy: Cache-Control: no-store

2.2 Discover Devices: GET /clock/findapi

An app or other client can call this endpoint first to obtain the IP addresses of clocks that may be on the current local network. It can then use each returned localIp to call the device's /get, /set, and other endpoints.

2.3 How It Works

Each clock periodically reports its public IP address, local IP address, and device information to the server. The discovery endpoint uses the caller's REMOTE_ADDR as its public IP address and queries for devices that meet all of the following conditions:

  1. The public IP reported by the device matches the caller's public IP
  2. The device has reported within the last 12 hours
  3. The device reported a valid local IPv4 address

Results are ordered by the most recent report time, newest first.

2.4 Request

http
GET /clock/findapi.php HTTP/1.1
Host: topyuan.top

The request has no query parameters or body. The server derives the public IP address from the current connection; a client cannot specify a public IP address to query.

bash
curl -i https://topyuan.top/clock/findapi

2.5 Successful Response

  • Status: 200 OK
  • Content-Type: application/json; charset=utf-8
  • Access-Control-Allow-Origin: *
  • Body: JSON array
  • Cache policy: Cache-Control: no-store
json
[
  {
    "chipId": "9730432",
    "localIp": "192.168.31.247",
    "deviceType": "ClockWise Plus",
    "lastSeen": "2026-08-04 15:26:30"
  },
  {
    "chipId": "10557104",
    "localIp": "192.168.31.180",
    "deviceType": "SuperY",
    "lastSeen": "2026-08-04 15:20:12"
  }
]
JSON FieldTypeDescription
chipIdStringClock chip ID
localIpStringLocal IPv4 address reported by the clock, for example 192.168.1.50
deviceTypeStringClockWise Plus, SuperY, or SuperY Lite
lastSeenStringTime of the last report recorded by the server, in YYYY-MM-DD HH:mm:ss format

The Device API documented on this page applies to devices whose deviceType is ClockWise Plus. If you also use my other clock models, the Cloud Discovery API may return those device types as well.

If no devices are found, the endpoint returns an empty array:

json
[]

2.6 Error Responses

StatusExample ResponseMeaning
400{"error":"invalid_client_ip"}The server could not obtain a valid client IP address
405{"error":"method_not_allowed"}A method other than GET or OPTIONS was used
500{"error":"discovery_unavailable"}Server error

2.7 Discovery Limitations

A matching public IP address only indicates that devices may be on the same local network; it is not definitive proof. Carrier-grade NAT (CGNAT), enterprise networks, campus networks, VPNs, or proxies may cause unrelated clients to share a public IP address. Conversely, different IPv4 and IPv6 egress paths may prevent devices on the same local network from matching.

This endpoint enables wildcard CORS, so browser-based web apps can call it cross-origin. It accepts GET and OPTIONS; browser preflight requests receive 204 No Content.

3. Device API Conventions

This section and all subsequent device endpoints are served by the clock's ESP32. They are independent of the public Cloud Discovery API described in Section 2.

3.1 Connection and Data Format

  • Base URL: http://<clock-local-ip>, for example http://192.168.1.50
  • Service location: clock ESP32
  • Port: 80
  • Transport: HTTP; HTTPS is not supported
  • Authentication: none
  • Write format: application/x-www-form-urlencoded; JSON request bodies are not supported
  • Successful response: read and control endpoints usually return 204 No Content with an empty body
  • Character encoding: string parameters use UTF-8 and must be URL-encoded
  • CORS: the firmware does not return CORS headers

Security notice: Any client that can reach the clock's local IP address can change settings, restart the device, or erase its Wi-Fi credentials. Expose these endpoints only on a trusted local network. Never forward them directly to the public internet.

3.2 Why Data Is Returned in HTTP Headers

Because the ESP32 has constrained runtime memory and response-buffer capacity, and JSON encoding adds processing overhead, the firmware does not use a conventional JSON response body. Instead, it places configuration values directly in HTTP response headers and returns an empty 204 No Content response. This is an implementation trade-off for a resource-constrained embedded device, not a conventional REST API design. Third-party clients must read the response headers and must not rely on a response body or JSON parsing.

3.3 Device Endpoint Overview

All paths in the following table are relative to http://<clock-local-ip>:

MethodPathPurposeSuccessful Response
GET/getRead all current configuration and device information204; data is in the response headers
POST/setChange one or more configuration values204; no response body
GET/read?pin=<GPIO>Read the ADC value of a specified GPIO204; result is in the pin response header
POST/restartRestart the device immediately204; the connection then closes
POST/eraseErase the Wi-Fi SSID and password, then restart204; the connection then closes

3.4 Important Compatibility Notes

  1. HTTP header names are case-insensitive. Some clients automatically convert displayBright to displaybright; clients must perform case-insensitive header lookups.
  2. Data from /get and /read is returned in response headers. The response body is always empty; do not attempt to parse it as JSON.
  3. The device firmware does not return CORS headers. A web page loaded from a different origin—another domain, port, or protocol—cannot read these responses directly in a browser. Native apps, backend services, command-line clients, and the clock's own web UI are not subject to this restriction.
  4. /set does not return per-field validation results. Unknown fields are ignored; some invalid numeric values are corrected, while others may be converted to 0 or truncated. Call /get after writing to verify the effective values.
  5. A + in form data is interpreted as a space. For example, the +8:00 time-zone offset must be encoded as %2B8%3A00. Use curl --data-urlencode to encode values automatically.
  6. /set supports partial updates: omitted fields remain unchanged. Fields whose values are empty strings are also treated as omitted, so the current API cannot clear a string-valued setting.

4. Read All Configuration: GET /get

Request

http
GET /get HTTP/1.1
Host: 192.168.1.50

The request has no parameters or body.

Response

The status is 204 No Content, and all data is returned in custom response headers. This avoids the additional processing and memory overhead of generating and buffering a JSON response on the ESP32. For example:

http
HTTP/1.1 204 No Content
displayBright: 205
autoBrightMin: 30
autoBrightMax: 2000
wifiSsid: MyWiFi
ntpFailRestart: 1
clockFace: 1
autoChange: 1
autoInterval: 0
version: 4.2

The complete header list follows. A default value is the firmware default used on first boot or when that setting has not yet been saved.

Response HeaderTypeMeaning and ValuesDefaultCorresponding /set Field
displayBrightIntegerDisplay brightness, 0255. Used as the daytime or maximum brightness in automatic and scheduled modes205displayBright
autoBrightMinIntegerNighttime LDR threshold for automatic brightness, 130030Combined with autoBrightMax as autoBright
autoBrightMaxIntegerBright-environment LDR threshold for automatic brightness, 80040952000Combined with autoBrightMin as autoBright
specialLedEnum integerLED panel color order: 0 RGB, 1 RBG, 2 GBR0specialLed
use24hFormatBoolean integer1 for 24-hour time; 0 for 12-hour time1use24hFormat
ldrPinIntegerGPIO connected to the photoresistor; the current hardware page specifies GPIO 3535ldrPin
wifiSsidStringSSID of the Wi-Fi network to which the device is currently connectedCurrent connectionRead-only
ntpServerStringNTP server hostname or IP addressntp2.aliyun.comntpServer
ntpFailRestartBoolean integer1 enables restart after repeated NTP failures; 0 disables it. After at least one successful synchronization, 24 consecutive failed synchronization attempts restart the device; any successful synchronization resets the failure count1ntpFailRestart
displayRotationEnum integerDisplay rotation: 0=0°, 1=90°, 2=180°, 3=270°0displayRotation
clockFaceEnum integerCurrent clock-face number, 127; see the clock-face table1clockFace
languageEnum integerConfiguration UI language: 0 Chinese, 1 English0language
totalYearIntegerAccumulated runtime, years component0Read-only
totalMonthIntegerAccumulated runtime, months component0Read-only
totalDayIntegerAccumulated runtime, days component0Read-only
brightMethodEnum integerBrightness mode: 0 ambient-light adjustment, 1 scheduled adjustment, 2 fixed brightness0brightMethod
nightLevelIntegerNighttime brightness level in scheduled mode, 151nightLevel
nightStarthIntegerHour when the nighttime period starts; recommended range 02322nightStarth
nightStartmIntegerMinute when the nighttime period starts; recommended range 0590nightStartm
nightEndhIntegerHour when the nighttime period ends; recommended range 0238nightEndh
nightEndmIntegerMinute when the nighttime period ends; recommended range 0590nightEndm
sqtextStringDisplay value for a fixed UTC offset, such as +8:00 or -3:30; used when timemode=0+8:00sqtext
timemodeEnum integerTime-zone mode: 0 fixed UTC offset, 1 POSIX time zone with daylight-saving rules0timemode
posixStringPOSIX TZ string passed to the clock library<+8>-8posix
autoChangeEnum integerAutomatic clock-face mode: 0 disabled, 1 sequential, 2 random; the schedule is controlled by autoInterval1autoChange
autoIntervalIntegerAutomatic clock-face interval in minutes; effective only when autoChange is not 0. 0 means daily at 00:00; other valid values are multiples of 10 from 10 through 1440. This HTTP field corresponds to the internal firmware setting autoChangeInterval0autoInterval
faceControlString27-character clock-face enable mask; left to right corresponds to faces 1–27, where 1 enables and 0 disables a face27 1 charactersfaceControl
reversePhaseBoolean integerHUB75 clock phase: 1 inverted, 0 normal0reversePhase
nightModeEnum integerNighttime behavior: 0 none, 1 turn off the LED panel, 2 show the oversized clock2nightMode
superColorIntegerOversized-clock color as a decimal RGB565 value, 06553516936superColor
versionStringCurrent firmware versionCurrent versionRead-only

Command-line example:

bash
curl -i http://192.168.1.50/get

5. Change Configuration: POST /set

Request Format

http
POST /set HTTP/1.1
Host: 192.168.1.50
Content-Type: application/x-www-form-urlencoded

displayBright=180&use24hFormat=1

A single request may include one or more fields. On success, the endpoint returns 204 No Content with no response body and does not echo the resulting configuration in custom headers.

Writable Fields

Form FieldInput FormatValid/Recommended ValuesDescription
displayBrightDecimal integer0255Set display brightness
autoBrightFixed-format stringMMMM,XXXXSet the minimum and maximum LDR thresholds together; both values must be four digits, for example 0030,2000
specialLedInteger0, 1, or 2RGB / RBG / GBR panel color order
reversePhaseBoolean string0 or 1Invert the panel phase
use24hFormatBoolean string0 or 1Use 24-hour time
ldrPinInteger35 on the current hardwareChange the photoresistor GPIO; the firmware does not verify that the pin supports ADC
ntpServerStringValid NTP hostname or IP addressSynchronize immediately after changing the server
ntpFailRestartBoolean string0 or 1Restart after 24 consecutive NTP synchronization failures; failures are counted only after the device has synchronized successfully at least once
displayRotationInteger03Represent 0°, 90°, 180°, and 270°, respectively
clockFaceInteger127Switch the current clock face
languageInteger0 or 1Change the configuration UI language; takes effect after reopening the configuration page
brightMethodInteger0, 1, or 2Automatic, scheduled, or fixed brightness
nightLevelInteger15Values outside the range are changed to 1
nightStarthInteger023Nighttime start hour; the firmware does not range-check this field
nightStartmInteger059Nighttime start minute; the firmware does not range-check this field
nightEndhInteger023Nighttime end hour; the firmware does not range-check this field
nightEndmInteger059Nighttime end minute; the firmware does not range-check this field
sqtextURL-encoded stringFor example +8:00Display value for fixed-offset mode; submit it together with posix
timemodeInteger0 or 1Fixed offset or daylight-saving-aware mode
posixURL-encoded stringValid POSIX TZ stringThe firmware does not validate the syntax; validate it in the client using the regular expression below
autoChangeInteger0, 1, or 2Disable, sequential, or random clock-face switching
autoIntervalInteger0, or a multiple of 10 from 10 through 1440Automatic clock-face interval in minutes; effective only when autoChange is not 0, and 0 means daily at 00:00. This HTTP field corresponds to the internal firmware setting autoChangeInterval
faceControl27-character stringOnly 0 and 1Character N controls clock face N; enabling at least two faces is recommended
nightModeInteger0, 1, or 2No action, turn off the display, or show the oversized clock
superColorDecimal integer065535RGB565 color for the oversized clock

wifiSsid, totalYear, totalMonth, totalDay, and version are read-only; submitting them to /set has no effect. autoBrightMin and autoBrightMax also cannot be submitted independently; use the combined autoBright field.

Regular expression for validating posix:

^([a-zA-Z]{1,6}|<[a-zA-Z0-9+-]{1,6}>)([+-]?([0-9]|1[0-4])(:[0-5]\d)?)((([a-zA-Z]{1,6}|<[a-zA-Z0-9+-]{1,6}>)([+-]?([0-9]|1[0-4])(:[0-5]\d)?)?)(,M([1-9]|1[0-2]).([1-5]).([0-6])(/([0-9]|1[0-9]|2[0-4])(:[0-5]\d)?)?,M([1-9]|1[0-2]).([1-5]).([0-6])(/([0-9]|1[0-9]|2[0-4])(:[0-5]\d)?)?)?)?$

5.1 Common Write Examples

Set brightness and 24-hour time:

bash
curl -i -X POST http://192.168.1.50/set \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data "displayBright=180&use24hFormat=1"

Set automatic-brightness thresholds. The exact autoBright format is a four-digit minimum, an ASCII comma, and a four-digit maximum:

bash
curl -i -X POST http://192.168.1.50/set \
  --data-urlencode "autoBright=0030,2000"

Set the NTP server and enable restart after 24 consecutive synchronization failures:

bash
curl -i -X POST http://192.168.1.50/set \
  --data-urlencode "ntpServer=ntp2.aliyun.com" \
  --data "ntpFailRestart=1"

Set a fixed UTC+8 time zone. Submit all three related fields in the same request:

bash
curl -i -X POST http://192.168.1.50/set \
  --data-urlencode "sqtext=+8:00" \
  --data-urlencode "timemode=0" \
  --data-urlencode "posix=<+8>-8"

Set a POSIX time zone with daylight-saving rules:

bash
curl -i -X POST http://192.168.1.50/set \
  --data-urlencode "timemode=1" \
  --data-urlencode "posix=EST5EDT,M3.2.0,M11.1.0"

Set the nighttime period to 22:30–07:00 and turn off the display at night:

bash
curl -i -X POST http://192.168.1.50/set \
  --data "nightLevel=1&nightStarth=22&nightStartm=30&nightEndh=7&nightEndm=0&nightMode=1"

Enable sequential automatic clock-face switching and allow only faces 1, 2, and 3 in the rotation:

bash
curl -i -X POST http://192.168.1.50/set \
  --data "autoChange=1&faceControl=111000000000000000000000000"

Change the clock face sequentially every 180 minutes:

bash
curl -i -X POST http://192.168.1.50/set \
  --data "autoChange=1&autoInterval=180"

Restore automatic clock-face switching to the daily 00:00 schedule:

bash
curl -i -X POST http://192.168.1.50/set \
  --data "autoInterval=0"

5.2 Firmware Coercion and Clamping Behavior

  • autoBright is parsed at fixed character offsets: the first four characters are the minimum and characters 6–9 are the maximum. Submit exactly nine characters in the form 0030,2000.
  • autoBrightMin values below 1 are changed to 1; values above 300 are changed to 300.
  • autoBrightMax values below 800 are changed to 800; values above 4095 are changed to 4095.
  • A nightLevel outside 15 is changed to 1.
  • Only the string 1 enables ntpFailRestart; any other non-empty value disables it. Submit only 0 or 1.
  • /set accepts autoInterval only when it is 0 or a multiple of 10 from 10 through 1440. An invalid value is ignored and the existing setting is retained. If an invalid saved value is loaded at startup, the firmware changes the in-memory value to 0.
  • A nonzero autoInterval is a relative interval. Its timer restarts when the device boots, when the automatic mode or interval changes, and after a manual clock-face change.
  • Most other integer parameters are not range-checked; clients must ensure that values are valid.
  • Unknown and read-only fields do not produce an error; the response may still be 204.

6. Read ADC: GET /read

Reads the raw analogRead() value for a specified GPIO. This can be used to obtain the ADC reading from the photoresistor.

Input

NameTypeRequiredDescription
pinIntegerYesGPIO number; the current hardware connects the LDR to GPIO 35 by default

Output

  • Status: 204 No Content
  • Response body: empty
  • Response header: pin: <raw-ADC-value>

Example:

bash
curl -i "http://192.168.1.50/read?pin=35"
http
HTTP/1.1 204 No Content
pin: 1842

The firmware converts the parameter to an unsigned 8-bit integer and passes it directly to analogRead() without checking whether the pin is valid. Third-party clients should not allow end users to supply an arbitrary GPIO number. Use the ldrPin returned by /get.

7. Restart the Device: POST /restart

This endpoint has no parameters or request body. The firmware attempts to send 204 and then immediately restarts.

bash
curl -i -X POST http://192.168.1.50/restart

The connection closes immediately during restart. Some clients may report a network disconnection before receiving the complete response.

8. Erase Wi-Fi Credentials: POST /erase

This endpoint has no parameters or request body. It erases only the saved Wi-Fi SSID and password, then immediately restarts the device.

bash
curl -i -X POST http://192.168.1.50/erase

After this call, the device is no longer reachable at its previous IP address and returns to the Wi-Fi provisioning flow. This is a destructive operation and should require confirmation before it is executed.

9. Clock-Face Numbers

NumberClock FaceNumberClock Face
1Super Mario15Shar Pei Dog
2Pac Man16Girl
3World Map17Kirby
4Time In Words18Labubu-Zimomo
5Clock Tower19Hello Kitty
6Pokedex20Twinkle Twinkle
7Retro Computer21Zootopia
8Snoopy22Minecraft-Village
9Nyan Cat23Codex
10Transformer24Rainy Window
11Minecraft-Torch25GTA VI
12Coffee26Zelda-Sunrise
13Pepsi27Particle Time
14Pikachu