Huawei: sleep breathing awareness for new devices. No sync

This commit is contained in:
Me7c7
2025-10-13 20:42:51 +03:00
parent 35ec0f2629
commit 1ee65b98f8
4 changed files with 121 additions and 12 deletions
@@ -733,6 +733,10 @@ public class HuaweiCoordinator {
return supportsCommandForService(0x20, 0x09);
}
public boolean supportsSleepBreath() {
return supportsCommandForService(0x2d, 0x01);
}
public boolean supportsExternalCalendarService() {
if (supportsExpandCapability())
return supportsExpandCapability(184);
@@ -894,9 +898,10 @@ public class HuaweiCoordinator {
return false;
}
public boolean supportsSleepBreath() {
//111 - resend capability
public boolean supportsSleepApnea() {
if (supportsExpandCapability())
return supportsExpandCapability(178); // 107
return supportsExpandCapability(107); // 178
return false;
}
@@ -918,12 +923,28 @@ public class HuaweiCoordinator {
return false;
}
public boolean supportsArrhythmia() {
public boolean supportsArrhythmiaOther() {
if (supportsExpandCapability())
return supportsExpandCapability(168); // 113
return supportsExpandCapability(113);
return false;
}
public boolean supportsArrhythmiaCE() {
if (supportsExpandCapability())
return supportsExpandCapability(255);
return false;
}
public boolean supportsArrhythmiaCN() {
if (supportsExpandCapability())
return supportsExpandCapability(168);
return false;
}
public boolean supportsArrhythmia() {
return supportsArrhythmiaCE() || supportsArrhythmiaCN() || supportsArrhythmiaOther();
}
public boolean supportsECG() {
if (supportsExpandCapability())
return supportsExpandCapability(106); // 226
@@ -169,11 +169,10 @@ public class HuaweiSettingsCustomizer implements DeviceSpecificSettingsCustomize
}
final SwitchPreferenceCompat sleepBreath = handler.findPreference(PREF_HUAWEI_SLEEP_BREATH);
if (sleepBreath != null && !coordinator.supportsSleepBreath()) {
if (sleepBreath != null && !(coordinator.supportsSleepBreath() || coordinator.supportsSleepApnea())) {
sleepBreath.setVisible(false);
}
final SwitchPreferenceCompat reparseWorkout = handler.findPreference("huawei_reparse_workout_data");
if (reparseWorkout != null) {
reparseWorkout.setVisible(false);
@@ -141,6 +141,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.datasync.Huaw
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.datasync.HuaweiDataSyncEmotion;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.datasync.HuaweiDataSyncFindDevice;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.datasync.HuaweiDataSyncGoals;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.datasync.HuaweiDataSyncSleepApnea;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.p2p.HuaweiP2PAppIcon;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.p2p.HuaweiP2PCalendarService;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.p2p.HuaweiP2PCannedRepliesService;
@@ -310,6 +311,8 @@ public class HuaweiSupportProvider {
private HuaweiDataSyncArrhythmia huaweiDataSyncArrhythmia = null;
private HuaweiDataSyncSleepApnea huaweiDataSyncSleepApnea = null;
private HuaweiDataSyncEcg huaweiDataSyncEcg = null;
protected HuaweiOTAManager huaweiOTAManager = new HuaweiOTAManager(this);
@@ -879,6 +882,9 @@ public class HuaweiSupportProvider {
if (getHuaweiCoordinator().supportsECG() && getHuaweiCoordinator().isShowForceCountrySpecificFeatures(getCoordinator().getDevice())) {
huaweiDataSyncEcg = new HuaweiDataSyncEcg(HuaweiSupportProvider.this);
}
if(getHuaweiCoordinator().supportsSleepApnea()) {
huaweiDataSyncSleepApnea = new HuaweiDataSyncSleepApnea(HuaweiSupportProvider.this);
}
// All of the below check that they are supported and otherwise they skip themselves
final List<Request> initRequestQueue = new ArrayList<>();
@@ -2301,12 +2307,24 @@ 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);
if(huaweiDataSyncSleepApnea != null) {
boolean sleepBreathSwitch = GBApplication
.getDeviceSpecificSharedPrefs(this.getDevice().getAddress())
.getBoolean(HuaweiConstants.PREF_HUAWEI_SLEEP_BREATH, false);
if(!huaweiDataSyncSleepApnea.changeSleepBreatheState(sleepBreathSwitch)) {
LOG.error("Failed to configure sleep breathing");
}
if(!huaweiDataSyncSleepApnea.changeSleepApneaState(sleepBreathSwitch)) {
LOG.error("Failed to configure sleep apnea");
}
} else {
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);
}
}
}
@@ -0,0 +1,71 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.datasync;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiTLV;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
public class HuaweiDataSyncSleepApnea implements HuaweiDataSyncCommon.DataCallback {
private final Logger LOG = LoggerFactory.getLogger(HuaweiDataSyncSleepApnea.class);
private final HuaweiSupportProvider support;
public static final String SRC_PKG_NAME = "hw.health.apneajsmodule";
public static final String PKG_NAME = "hw.watch.health.osa";
public HuaweiDataSyncSleepApnea(HuaweiSupportProvider support) {
this.support = support;
this.support.getHuaweiDataSyncManager().registerCallback(PKG_NAME, this);
}
private boolean sendCommonData(int configId, byte configAction, byte[] configData) {
HuaweiDataSyncCommon.ConfigCommandData data = new HuaweiDataSyncCommon.ConfigCommandData();
HuaweiDataSyncCommon.ConfigData config = new HuaweiDataSyncCommon.ConfigData();
config.configId = configId;
config.configAction = configAction;
config.configData = configData;
List<HuaweiDataSyncCommon.ConfigData> list = new ArrayList<>();
list.add(config);
data.setConfigDataList(list);
return this.support.getHuaweiDataSyncManager().sendConfigCommand(SRC_PKG_NAME, PKG_NAME, data);
}
public boolean changeSleepBreatheState(boolean state) {
HuaweiTLV tlv = new HuaweiTLV().put(0x01, state);
return sendCommonData(900300008, (byte) 1, tlv.serialize());
}
public boolean changeSleepApneaState(boolean state) {
HuaweiTLV tlv = new HuaweiTLV().put(0x01, state);
return sendCommonData(900300007, (byte) 1, tlv.serialize());
}
public boolean querySleepApneaState(boolean state) {
HuaweiTLV tlv = new HuaweiTLV().put(0x01, state);
return sendCommonData(900300007, (byte) 2, tlv.serialize());
}
@Override
public void onConfigCommand(HuaweiDataSyncCommon.ConfigCommandData data) {
LOG.info("Handle SleepApnea command");
//TODO:
}
@Override
public void onEventCommand(HuaweiDataSyncCommon.EventCommandData data) {
}
@Override
public void onDataCommand(HuaweiDataSyncCommon.DataCommandData data) {
}
@Override
public void onDictDataCommand(HuaweiDataSyncCommon.DictDataCommandData data) {
}
}