From f76d64b20df5fd2482e93119e006693477fe74d9 Mon Sep 17 00:00:00 2001 From: Me7c7 Date: Sat, 16 Aug 2025 14:54:36 +0300 Subject: [PATCH] Huawei: Changed the sleep prefs and enabled sleep breathing awareness configuration Sleep breathing awareness can be enabled for some devices. Information is currently not retrieved from the watch. --- .../devices/huawei/HuaweiConstants.java | 1 + .../devices/huawei/HuaweiCoordinator.java | 6 ++++ .../huawei/HuaweiSettingsCustomizer.java | 8 +++++ .../devices/huawei/packets/Breath.java | 26 ++++++++++++++ .../devices/huawei/HuaweiSupportProvider.java | 16 +++++++++ .../requests/SendHROpenCloseRequest.java | 5 --- .../requests/SendSleepBreathRequest.java | 36 +++++++++++++++++++ app/src/main/res/values/strings.xml | 7 ++-- .../main/res/xml/devicesettings_trusleep.xml | 36 ++++++++++++------- 9 files changed, 120 insertions(+), 21 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Breath.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendSleepBreathRequest.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiConstants.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiConstants.java index 1c8718119e..25c4ca6905 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiConstants.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiConstants.java @@ -97,6 +97,7 @@ public final class HuaweiConstants { public static final String PREF_HUAWEI_ADDRESS = "huawei_address"; public static final String PREF_HUAWEI_WORKMODE = "workmode"; public static final String PREF_HUAWEI_TRUSLEEP = "trusleep"; + public static final String PREF_HUAWEI_SLEEP_BREATH = "huawei_sleep_breath"; public static final String PREF_HUAWEI_ACCOUNT = "huawei_account"; public static final String PREF_HUAWEI_DND_LIFT_WRIST_TYPE = "dnd_lift_wrist_type"; // SharedPref for 0x01 0x1D public static final String PREF_HUAWEI_DEBUG_REQUEST = "debug_huawei_request"; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiCoordinator.java index 7029fd81fe..aebed10cde 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiCoordinator.java @@ -871,6 +871,12 @@ public class HuaweiCoordinator { return false; } + public boolean supportsSleepBreath() { + if (supportsExpandCapability()) + return supportsExpandCapability(178); // 107 + return false; + } + public boolean supportsPromptPushMessage () { // do not ask for capabilities under specific condition // if (deviceType == 10 && deviceVersion == 73617766697368 && deviceSoftVersion == 372E312E31) -> leo device diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiSettingsCustomizer.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiSettingsCustomizer.java index 6116d8177e..637c80d4a8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiSettingsCustomizer.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiSettingsCustomizer.java @@ -48,6 +48,7 @@ import static nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiConstant import static nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiConstants.PREF_HUAWEI_HEART_RATE_HIGH_ALERT; import static nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiConstants.PREF_HUAWEI_HEART_RATE_LOW_ALERT; import static nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiConstants.PREF_HUAWEI_HEART_RATE_REALTIME_MODE; +import static nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiConstants.PREF_HUAWEI_SLEEP_BREATH; import static nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiConstants.PREF_HUAWEI_SPO_LOW_ALERT; import static nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiConstants.PREF_HUAWEI_STRESS_CALIBRATE; import static nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiConstants.PREF_HUAWEI_STRESS_SWITCH; @@ -116,6 +117,7 @@ public class HuaweiSettingsCustomizer implements DeviceSpecificSettingsCustomize handler.addPreferenceHandlerFor(PREF_HUAWEI_WORKMODE); handler.addPreferenceHandlerFor(PREF_HUAWEI_TRUSLEEP); + handler.addPreferenceHandlerFor(PREF_HUAWEI_SLEEP_BREATH); handler.addPreferenceHandlerFor(PREF_HUAWEI_DEBUG_REQUEST); handler.addPreferenceHandlerFor(PREF_HUAWEI_CONTINUOUS_SKIN_TEMPERATURE_MEASUREMENT); handler.addPreferenceHandlerFor(PREF_HUAWEI_HEART_RATE_REALTIME_MODE); @@ -147,6 +149,12 @@ public class HuaweiSettingsCustomizer implements DeviceSpecificSettingsCustomize forceSpO2.setVisible(!supportsSpO2); } + final SwitchPreferenceCompat sleepBreath = handler.findPreference(PREF_HUAWEI_SLEEP_BREATH); + if(sleepBreath != null && !coordinator.supportsSleepBreath()) { + sleepBreath.setVisible(false); + } + + final SwitchPreferenceCompat reparseWorkout = handler.findPreference("huawei_reparse_workout_data"); if (reparseWorkout != null) { reparseWorkout.setVisible(false); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Breath.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Breath.java new file mode 100644 index 0000000000..bcb7c86577 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Breath.java @@ -0,0 +1,26 @@ +package nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets; + +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket; +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiTLV; + +public class Breath { + public static final byte id = 0x2d; + + public static class SleepBreath { + public static final byte id = 0x01; + + public static class Request extends HuaweiPacket { + public Request(ParamsProvider paramsProvider, byte type) { + super(paramsProvider); + + this.serviceId = Breath.id; + this.commandId = id; + + this.tlv = new HuaweiTLV().put(0x1, type); + + this.isEncrypted = true; + this.complete = true; + } + } + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java index d188bb0cb5..f4f583c334 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java @@ -167,6 +167,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.Send import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendSetContactsRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendNotifyHeartRateCapabilityRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendNotifyRestHeartRateCapabilityRequest; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendSleepBreathRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SetAutomaticHeartrateRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SetAutomaticSpoRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SetDisconnectNotification; @@ -882,6 +883,7 @@ public class HuaweiSupportProvider { initRequestQueue.add(new SetDateFormatRequest(this)); initRequestQueue.add(new SetActivityReminderRequest(this)); initRequestQueue.add(new SetTruSleepRequest(this)); + initRequestQueue.add(new SendSleepBreathRequest(this)); initRequestQueue.add(new GetContactsCount(this)); initRequestQueue.add(new SendOTASetAutoUpdate(this)); initRequestQueue.add(new GetOTAChangeLog(this)); @@ -1113,6 +1115,10 @@ public class HuaweiSupportProvider { setTrusleep(); break; } + case HuaweiConstants.PREF_HUAWEI_SLEEP_BREATH: { + setSleepBreath(); + break; + } case HuaweiConstants.PREF_HUAWEI_CONTINUOUS_SKIN_TEMPERATURE_MEASUREMENT: { setContinuousSkinTemperatureMeasurement(); break; @@ -2305,6 +2311,16 @@ public class HuaweiSupportProvider { } } + public void setSleepBreath() { + try { + SendSleepBreathRequest setSleepBreathReq = new SendSleepBreathRequest(this); + setSleepBreathReq.doPerform(); + } catch (IOException e) { + GB.toast(context, "Failed to configure sleep breathing awareness", Toast.LENGTH_SHORT, GB.ERROR, e); + LOG.error("Failed to configure sleep breathing awareness", e); + } + } + public void setTemperatureUnit() { try { SetTemperatureUnitSetting setTemperatureUnitSetting = new SetTemperatureUnitSetting(this); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendHROpenCloseRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendHROpenCloseRequest.java index 00026b7c4d..367a0a5080 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendHROpenCloseRequest.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendHROpenCloseRequest.java @@ -16,9 +16,6 @@ along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.List; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket; @@ -26,8 +23,6 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.HrRriTest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider; public class SendHROpenCloseRequest extends Request { - private static final Logger LOG = LoggerFactory.getLogger(SendHROpenCloseRequest.class); - private final byte type; public SendHROpenCloseRequest(HuaweiSupportProvider support, byte type) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendSleepBreathRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendSleepBreathRequest.java new file mode 100644 index 0000000000..6c13989c4e --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendSleepBreathRequest.java @@ -0,0 +1,36 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests; + +import java.util.List; + +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiConstants; +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket; +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Breath; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider; + +public class SendSleepBreathRequest extends Request { + + public SendSleepBreathRequest(HuaweiSupportProvider support) { + super(support); + this.serviceId = Breath.id; + this.commandId = Breath.SleepBreath.id; + } + + @Override + protected boolean requestSupported() { + return supportProvider.getHuaweiCoordinator().supportsSleepBreath(); + } + + @Override + protected List createRequest() throws Request.RequestCreationException { + boolean sleepBreathSwitch = GBApplication + .getDeviceSpecificSharedPrefs(this.getDevice().getAddress()) + .getBoolean(HuaweiConstants.PREF_HUAWEI_SLEEP_BREATH, false); + byte type = (byte) (sleepBreathSwitch?2:0); + try { + return new Breath.SleepBreath.Request(paramsProvider, type).serialize(); + } catch (HuaweiPacket.CryptoException e) { + throw new Request.RequestCreationException(e); + } + } +} \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8a69793078..924b1b7ce7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3340,10 +3340,11 @@ Work Mode Do not uncheck smart wakeup checkbox. Do not check smart wakeup checkbox. - HUAWEI TruSleep ™ - Monitor your sleep quality and breathing pattern in real time.\nAnalyze your sleep patterns and accurately diagnose 6 types of sleeping problems. + HUAWEI TruSleep™ + Monitor your sleep quality in real time. Improved sleep monitoring - Warning: enabling this will make all sleep show up as light sleep in Gadgetbridge! Click here if you accept this. + Warning: TruSleep™ is not fully implemented. Enabling it on some devices will cause all sleep data to show up as light sleep in Gadgetbridge! + Assess your breathing in a quiet environment. May affect battery life.\nWarning: Not synced to the Gadgetbridge yet. Activity recognition settings recognize running recognize biking diff --git a/app/src/main/res/xml/devicesettings_trusleep.xml b/app/src/main/res/xml/devicesettings_trusleep.xml index 912e0e1328..d4e6fb4661 100644 --- a/app/src/main/res/xml/devicesettings_trusleep.xml +++ b/app/src/main/res/xml/devicesettings_trusleep.xml @@ -4,23 +4,33 @@ android:icon="@drawable/ic_activity_sleep" android:key="screen_trusleep" android:persistent="false" - android:title="@string/huawei_trusleep_title" - android:summary="@string/huawei_trusleep_summary_light"> + android:summary="@string/huawei_trusleep_summary_light" + android:title="@string/huawei_trusleep_title"> + android:persistent="false" + android:selectable="false" + android:summary="@string/huawei_trusleep_warning" + android:title="@string/huawei_trusleep_title" /> - + + + -