From cbe4226a76194ffeb613d6257ed2cba0c0640cd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Rebelo?= Date: Sun, 10 May 2026 15:48:18 +0100 Subject: [PATCH] Experimental support for Amazfit Active 3 Premium, Cheetah 2 Pro, T-Rex Ultra 2 --- CHANGELOG.md | 1 + .../huami/zeppos/ZeppOsCoordinator.java | 2 +- .../AmazfitActive3PremiumCoordinator.java | 94 +++++++++++++++++++ .../AmazfitCheetah2ProCoordinator.java | 93 ++++++++++++++++++ .../watches/AmazfitTRexUltra2Coordinator.java | 83 ++++++++++++++++ .../gadgetbridge/model/DeviceType.java | 6 ++ .../huami/zeppos/ZeppOsDeviceSources.kt | 18 +++- app/src/main/res/values/strings.xml | 3 + app/src/main/res/xml/changelog_master.xml | 1 + .../metadata/android/en-US/changelogs/247.txt | 2 +- 10 files changed, 300 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/zeppos/watches/AmazfitActive3PremiumCoordinator.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/zeppos/watches/AmazfitCheetah2ProCoordinator.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/zeppos/watches/AmazfitTRexUltra2Coordinator.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 7622dc4763..87b25f32de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ * Initial support for Redmi Buds 8 Active * Initial support for iTECH Active 3 (MoYoung / Da Fit) * Initial support for ZL02D (MoYoung / Da Fit) +* Experimental support for Amazfit Active 3 Premium, Cheetah 2 Pro, T-Rex Ultra 2 * Experimental support for Sony WH-1000XM6 * Add and adjust default sleep range to 18:00 * Add auto export of gpx files diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/zeppos/ZeppOsCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/zeppos/ZeppOsCoordinator.java index d699aeecd0..7f67784b4c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/zeppos/ZeppOsCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/zeppos/ZeppOsCoordinator.java @@ -661,7 +661,7 @@ public abstract class ZeppOsCoordinator extends HuamiCoordinator { } public boolean supportsFtpServer(final GBDevice device) { - return false; + return supportsWifiHotspot(device); } public boolean hasGps(final GBDevice device) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/zeppos/watches/AmazfitActive3PremiumCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/zeppos/watches/AmazfitActive3PremiumCoordinator.java new file mode 100644 index 0000000000..3282878d95 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/zeppos/watches/AmazfitActive3PremiumCoordinator.java @@ -0,0 +1,94 @@ +/* Copyright (C) 2026 José Rebelo + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches; + +import androidx.annotation.NonNull; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.ZeppOsCoordinator; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; + +public class AmazfitActive3PremiumCoordinator extends ZeppOsCoordinator { + @Override + public boolean isExperimental() { + return true; + } + + @Override + public ConnectionType getConnectionType() { + return ConnectionType.BOTH; + } + + @Override + public List getDeviceBluetoothNames() { + // never seen, assumptions + return Arrays.asList( + "Amazfit Active 3 Premium", + "Active 3 Premium" + ); + } + + @Override + public Set getDeviceSources() { + return new HashSet<>(Arrays.asList( + 10944768, // chinese mainland version + 10944769, + 10944771, + 10948867 + )); + } + + @Override + public int getDeviceNameResource() { + return R.string.devicetype_amazfit_active_3_premium; + } + + @Override + public boolean mainMenuHasMoreSection() { + return false; + } + + @Override + public boolean supportsControlCenter() { + return true; + } + + @Override + public boolean supportsToDoList() { + return true; + } + + @Override + public boolean supportsWifiHotspot(final GBDevice device) { + return true; + } + + @Override + public boolean supportsBluetoothPhoneCalls(final GBDevice device) { + return true; + } + + @Override + public DeviceKind getDeviceKind(@NonNull GBDevice device) { + return DeviceKind.WATCH; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/zeppos/watches/AmazfitCheetah2ProCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/zeppos/watches/AmazfitCheetah2ProCoordinator.java new file mode 100644 index 0000000000..cf650542be --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/zeppos/watches/AmazfitCheetah2ProCoordinator.java @@ -0,0 +1,93 @@ +/* Copyright (C) 2026 José Rebelo + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches; + +import androidx.annotation.NonNull; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.ZeppOsCoordinator; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; + +public class AmazfitCheetah2ProCoordinator extends ZeppOsCoordinator { + @Override + public boolean isExperimental() { + return true; + } + + @Override + public ConnectionType getConnectionType() { + return ConnectionType.BOTH; + } + + @Override + public List getDeviceBluetoothNames() { + // never seen, assumption + return Arrays.asList( + "Amazfit Cheetah 2 Pro", + "Cheetah 2 Pro" + ); + } + + @Override + public Set getDeviceSources() { + return new HashSet<>(Arrays.asList( + 11010304, // chinese mainland version + 11010305, + 11010307 + )); + } + + @Override + public int getDeviceNameResource() { + return R.string.devicetype_amazfit_cheetah_2_pro; + } + + @Override + public boolean mainMenuHasMoreSection() { + return false; + } + + @Override + public boolean supportsControlCenter() { + return true; + } + + @Override + public boolean supportsToDoList() { + return true; + } + + @Override + public boolean supportsWifiHotspot(final GBDevice device) { + return true; + } + + @Override + public boolean supportsBluetoothPhoneCalls(final GBDevice device) { + return true; + } + + @Override + public DeviceKind getDeviceKind(@NonNull GBDevice device) { + return DeviceKind.WATCH; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/zeppos/watches/AmazfitTRexUltra2Coordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/zeppos/watches/AmazfitTRexUltra2Coordinator.java new file mode 100644 index 0000000000..7d3cf73a55 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/zeppos/watches/AmazfitTRexUltra2Coordinator.java @@ -0,0 +1,83 @@ +/* Copyright (C) 2026 José Rebelo + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches; + +import androidx.annotation.NonNull; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.ZeppOsCoordinator; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; + +public class AmazfitTRexUltra2Coordinator extends ZeppOsCoordinator { + @Override + public boolean isExperimental() { + return true; + } + + @Override + public List getDeviceBluetoothNames() { + // never seen, assumptions + return Arrays.asList( + "Amazfit T-Rex Ultra 2", + "T-Rex Ultra 2" + ); + } + + @Override + public Set getDeviceSources() { + return new HashSet<>(Arrays.asList( + 10879232, // chinese mainland version + 10879233, + 10879235 + )); + } + + @Override + public int getDeviceNameResource() { + return R.string.devicetype_amazfit_trex_ultra_2; + } + + @Override + public boolean supportsControlCenter() { + return true; + } + + @Override + public boolean supportsToDoList() { + return true; + } + + @Override + public boolean supportsWifiHotspot(final GBDevice device) { + return true; + } + + @Override + public boolean supportsBluetoothPhoneCalls(final GBDevice device) { + return true; + } + + @Override + public DeviceKind getDeviceKind(@NonNull GBDevice device) { + return DeviceKind.WATCH; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java index ad6e7be818..4cc38ad56f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java @@ -237,6 +237,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.straps.AmazfitH import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches.AmazfitActive2RoundCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches.AmazfitActive2NfcCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches.AmazfitActive2SquareCoordinator; +import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches.AmazfitActive3PremiumCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches.AmazfitActiveCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches.AmazfitActiveEdgeCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches.AmazfitActiveMaxCoordinator; @@ -247,6 +248,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches.Amazfit import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches.AmazfitBip5Coordinator; import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches.AmazfitBip5UnityCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches.AmazfitBip6Coordinator; +import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches.AmazfitCheetah2ProCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches.AmazfitCheetahProCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches.AmazfitCheetahRoundCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches.AmazfitCheetahSquareCoordinator; @@ -263,6 +265,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches.Amazfit import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches.AmazfitTRex3Coordinator; import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches.AmazfitTRex3Pro44mmCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches.AmazfitTRex3Pro48mmCoordinator; +import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches.AmazfitTRexUltra2Coordinator; import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches.AmazfitTRexUltraCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.watches.MiBand7Coordinator; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.freearc.HuaweiFreearcCoordinator; @@ -572,12 +575,14 @@ public enum DeviceType { AMAZFITBIP3(AmazfitBip3Coordinator.class), AMAZFITBIP3PRO(AmazfitBip3ProCoordinator.class), AMAZFITCHEETAHPRO(AmazfitCheetahProCoordinator.class), + AMAZFITCHEETAH2PRO(AmazfitCheetah2ProCoordinator.class), AMAZFITCHEETAHSQUARE(AmazfitCheetahSquareCoordinator.class), AMAZFITCHEETAHROUND(AmazfitCheetahRoundCoordinator.class), AMAZFITBIP5(AmazfitBip5Coordinator.class), AMAZFITBIP5UNITY(AmazfitBip5UnityCoordinator.class), AMAZFITBIP6(AmazfitBip6Coordinator.class), AMAZFITTREXULTRA(AmazfitTRexUltraCoordinator.class), + AMAZFITTREXULTRA2(AmazfitTRexUltra2Coordinator.class), AMAZFITGTRMINI(AmazfitGTRMiniCoordinator.class), AMAZFITFALCON(AmazfitFalconCoordinator.class), AMAZFITBALANCE(AmazfitBalanceCoordinator.class), @@ -587,6 +592,7 @@ public enum DeviceType { AMAZFITACTIVE2(AmazfitActive2RoundCoordinator.class), AMAZFITACTIVE2NFC(AmazfitActive2NfcCoordinator.class), AMAZFITACTIVE2SQUARE(AmazfitActive2SquareCoordinator.class), + AMAZFITACTIVE3PREMIUM(AmazfitActive3PremiumCoordinator.class), AMAZFITACTIVEEDGE(AmazfitActiveEdgeCoordinator.class), AMAZFITACTIVEMAX(AmazfitActiveMaxCoordinator.class), AMAZFITHELIORING(AmazfitHelioRingCoordinator.class), diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/ZeppOsDeviceSources.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/ZeppOsDeviceSources.kt index 1efb8344a1..afe575a85a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/ZeppOsDeviceSources.kt +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/ZeppOsDeviceSources.kt @@ -1,7 +1,8 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos object ZeppOsDeviceSources { - // jq '.[] | [.value.productId, .value.productVersion, .deviceSource] | @csv' -r devices.json + // jq '.[] | [.value.productId, .value.productVersion, .deviceSource] | @csv' -r devices.json | \ + // sed 's/,/, /g; s/^/ZeppOsDeviceInfo(/; s/$/),/' // TODO: A few are missing: mi band 7, amazfit band 7, amazfit gtr mini val DEVICE_SOURCES = listOf( ZeppOsDeviceInfo(94, 256, 224), @@ -15,6 +16,13 @@ object ZeppOsDeviceSources { ZeppOsDeviceInfo(115, 259, 247), ZeppOsDeviceInfo(116, 257, 251), ZeppOsDeviceInfo(117, 259, 254), + ZeppOsDeviceInfo(103, 256, 260), + ZeppOsDeviceInfo(103, 257, 261), + ZeppOsDeviceInfo(103, 258, 262), + ZeppOsDeviceInfo(103, 259, 263), + ZeppOsDeviceInfo(103, 260, 264), + ZeppOsDeviceInfo(103, 261, 265), + ZeppOsDeviceInfo(103, 262, 266), ZeppOsDeviceInfo(63, 256, 414), ZeppOsDeviceInfo(63, 257, 415), ZeppOsDeviceInfo(113, 256, 418), @@ -22,6 +30,7 @@ object ZeppOsDeviceSources { ZeppOsDeviceInfo(93, 258, 6095106), ZeppOsDeviceInfo(100, 256, 6553856), ZeppOsDeviceInfo(100, 257, 6553857), + ZeppOsDeviceInfo(103, 263, 6750471), ZeppOsDeviceInfo(120, 257, 7864577), ZeppOsDeviceInfo(121, 256, 7930112), ZeppOsDeviceInfo(121, 257, 7930113), @@ -82,6 +91,13 @@ object ZeppOsDeviceSources { ZeppOsDeviceInfo(163, 259, 10682627), ZeppOsDeviceInfo(165, 257, 10813697), ZeppOsDeviceInfo(165, 259, 10813699), + ZeppOsDeviceInfo(166, 256, 10879232), + ZeppOsDeviceInfo(166, 257, 10879233), + ZeppOsDeviceInfo(166, 259, 10879235), + ZeppOsDeviceInfo(167, 256, 10944768), + ZeppOsDeviceInfo(167, 257, 10944769), + ZeppOsDeviceInfo(167, 259, 10944771), + ZeppOsDeviceInfo(167, 4355, 10948867), ) fun resolve(productId: Int, productVersion: Int): ZeppOsDeviceInfo? { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8958f57029..c057802467 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1907,10 +1907,12 @@ Amazfit Active 2 (Round) Amazfit Active 2 (Square) Amazfit Active 2 NFC + Amazfit Active 3 Premium Amazfit Active Edge Amazfit Cheetah (Square) Amazfit Cheetah (Round) Amazfit Cheetah Pro + Amazfit Cheetah 2 Pro Amazfit GTS 3 Amazfit GTS 4 Amazfit GTS 4 Mini @@ -1929,6 +1931,7 @@ Amazfit T-Rex 3 Pro (44mm) Amazfit T-Rex 3 Pro (48mm) Amazfit T-Rex Ultra + Amazfit T-Rex Ultra 2 Amazfit Band 5 Amazfit Band 7 Amazfit Neo diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index 2e00f54cda..1531373357 100644 --- a/app/src/main/res/xml/changelog_master.xml +++ b/app/src/main/res/xml/changelog_master.xml @@ -10,6 +10,7 @@ Initial support for Redmi Buds 8 Active Initial support for iTECH Active 3 (MoYoung / Da Fit) Initial support for ZL02D (MoYoung / Da Fit) + Experimental support for Amazfit Active 3 Premium, Cheetah 2 Pro, T-Rex Ultra 2 Experimental support for Sony WH-1000XM6 Add and adjust default sleep range to 18:00 Add auto export of gpx files diff --git a/src/mainline/fastlane/metadata/android/en-US/changelogs/247.txt b/src/mainline/fastlane/metadata/android/en-US/changelogs/247.txt index a24cb3cf41..345e8ddb3d 100644 --- a/src/mainline/fastlane/metadata/android/en-US/changelogs/247.txt +++ b/src/mainline/fastlane/metadata/android/en-US/changelogs/247.txt @@ -1,4 +1,4 @@ -• Support for 14 new devices +• Support for 17 new devices • Auto export of GPX files • FossWallet support • Fossil Q: extensive improvements - find device, vibrate on call, hand calibration, button actions, music/volume control, and more