Custom watchface for Amazfit Active 3 Pro (Zepp OS 4.3)
- JavaScript 86.2%
- Python 9.2%
- HTML 2.8%
- Shell 1.8%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
- Add deviceSources 10813697/10813699 (Active Max) to clear and modular_v4 app.json - build.sh: default device is now Active Max; add --help with device shortcuts (max/a3p) - modular_v4: fix side arc clipping on Active Max — reduce radius from px(240) to px(234), giving ~6px inset from the 240px circular display boundary (accounts for designWidth OS scaling 480/466 ≈ 1.030 that was causing the outer arc edge to exceed the display radius) - modular_v4/DateSlotWidget: add transparent tap area opening SYSTEM_APP_CALENDAR Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
| clear | ||
| modular | ||
| modular_v4 | ||
| .gitignore | ||
| build.sh | ||
| CLAUDE.md | ||
| gen_preview.py | ||
| README.md | ||
active3pro-face
Custom watchface for the Amazfit Active 3 Pro built with Zeus CLI and Zepp OS API 4.3.
Features
- Time & date — large centered display
- Left column (arc 11→7 o'clock):
- Weather widget (temperature, dynamic icon) → tap opens Weather app
- Heart rate (pink dotted ring, heart icon) → tap opens Heart Rate app
- Battery (green segment ring, battery icon)
- Stress (blue→yellow→orange→red gradient ring, person icon) → tap opens Stress app
- Bezel arcs (right side):
- Steps: 12→3 o'clock (cyan, 20 levels) → tap opens Activity app
- Calories: 6→3 o'clock (orange, 20 levels) → tap opens Training Status app
Structure
watchface/index.js main watchface logic
assets/active3pro/ PNG assets (rings, icons, bezel arcs)
setting/index.js settings page
app.json app manifest (appId 1126258)
build.sh build + QR publish script
Build & Publish
build.sh does everything in one step:
bash build.sh
It will:
- Run
zeus previewfor the Amazfit Active 3 Premium target - Convert the terminal QR block characters to a PNG (
cell = 8 px/module) - Write the PNG to
/var/www/html/nerd-department/zeus-qr.png - Update the expiry timestamp in
zeus-qr.html
Then scan the QR at https://nerd-department.de/zeus-qr.html with the Zepp app.
Prerequisites:
| Dependency | Version |
|---|---|
| Node.js (via nvm) | v24 at /root/.nvm/versions/node/v24.20.0/bin |
@zeppos/zeus-cli |
1.9.3 (installed in project) |
| Python 3 + Pillow | system Python, pip install pillow |
Asset generation
All ring/arc PNGs are generated via numpy + Pillow and converted to TGA by zeus at build time. Zeus supports RGBA PNG → TGA conversion automatically; no manual step is needed.
| Asset group | Size | Description |
|---|---|---|
bat_0..10.png |
100×100 | Green 10-segment battery ring (32° segments, 4° gaps) |
bat_icon_0..3.png |
22×32 | Upright battery outline with 0–3 green fill segments |
hr_ring.png |
100×100 | 24 pink dots at 15° intervals, gap at 6 o'clock (±25°) |
stress_track.png |
100×100 | Smooth blue→yellow→orange→red gradient ring |
stress_marker_0..10.png |
100×100 | White dot marker at each stress level position |
step_0..20.png |
234×234 | Cyan bezel arc 12→3 o'clock, LW=18, rounded caps |
cal_0..20.png |
234×234 | Orange bezel arc 6→3 o'clock, LW=18, rounded caps |
heart.png |
28×24 | Heart icon (pink) |
shoe.png |
~24px | Shoe/footstep icon (cyan) |
flame.png |
~24px | Flame icon (orange) |
person_heart.png |
32×36 | Person silhouette + small heart |
weather.png |
~36px | Cloud/weather icon (blue) |
Ring geometry
SIZE = 100 px, cx = cy = 49
R_MID = 42, LW = 9
ring_mask: |dist(px, center) - R_MID| <= LW/2
Clockwise progress (image coords, y-axis down):
progress = (img_angle_0360 - START_ANGLE + 360) % 360
Permissions (app.json)
data:user.hd.heart_rate
data:user.hd.battery
data:user.hd.step
data:user.hd.calorie
data:user.hd.weather
data:user.hd.stress
App launch (tap navigation)
Tapping a widget opens the corresponding system app via launchApp({ appId, native: true }) from @zos/router (API level ≥ 3.0). Named constants are used — no hardcoded numeric IDs.
| Widget | Constant | App |
|---|---|---|
| Weather | SYSTEM_APP_WEATHER |
Weather |
| Heart rate | SYSTEM_APP_HR |
Heart Rate |
| Stress | SYSTEM_APP_PRESSURE |
Stress / Mental load (压力) |
| Steps | SYSTEM_APP_STATUS |
Activity |
| Calories | SYSTEM_APP_SPORT_STATUS |
Training Status |
Note:
SYSTEM_APP_PRESSURE= 压力 (yālì) = mental stress on Amazfit devices, not the barometric pressure sensor.SYSTEM_APP_STRESSdoes not exist in this API.
Sensor notes
ARC_PROGRESSwidget does not render on this device — all progress is PNG-based.Stress.getCurrent()returns{ value, time }— use.value, not the object directly.Weather.getForecastWeather()is the correct API (v4.x);getForecast()is the legacy fallback.forecastDatamay be an array or{ data: [], count }depending on firmware — both cases handled.Stressis imported viaimport * as _sensor from '@zos/sensor'to avoid a module-level crash if the sensor is unavailable on the device at runtime.