Custom watchface for Amazfit Active 3 Pro (Zepp OS 4.3)
  • JavaScript 86.2%
  • Python 9.2%
  • HTML 2.8%
  • Shell 1.8%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Gunar Ernis d28690334a feat: Active Max support + arc alignment fix + calendar tap
- 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>
2026-09-18 20:26:08 +02:00
clear feat: Active Max support + arc alignment fix + calendar tap 2026-09-18 20:26:08 +02:00
modular modular_v4: API 4.x port mit fixes für PAI, Sleep, Weather, Arc-Hintergrund 2026-09-13 11:47:35 +02:00
modular_v4 feat: Active Max support + arc alignment fix + calendar tap 2026-09-18 20:26:08 +02:00
.gitignore Ignore dist/ in all subdirectories 2026-09-08 18:33:23 +02:00
build.sh feat: Active Max support + arc alignment fix + calendar tap 2026-09-18 20:26:08 +02:00
CLAUDE.md modular_v4: API 4.x port mit fixes für PAI, Sleep, Weather, Arc-Hintergrund 2026-09-13 11:47:35 +02:00
gen_preview.py modular_v4: API 4.x port mit fixes für PAI, Sleep, Weather, Arc-Hintergrund 2026-09-13 11:47:35 +02:00
README.md Add tap-to-launch for all widgets using @zos/router SYSTEM_APP constants 2026-09-06 17:33:16 +02:00

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:

  1. Run zeus preview for the Amazfit Active 3 Premium target
  2. Convert the terminal QR block characters to a PNG (cell = 8 px/module)
  3. Write the PNG to /var/www/html/nerd-department/zeus-qr.png
  4. 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_STRESS does not exist in this API.

Sensor notes

  • ARC_PROGRESS widget 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.
  • forecastData may be an array or { data: [], count } depending on firmware — both cases handled.
  • Stress is imported via import * as _sensor from '@zos/sensor' to avoid a module-level crash if the sensor is unavailable on the device at runtime.