1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-12-29 12:05:53 +01:00

Blood Pressure calibration

This commit is contained in:
mamutcho 2019-11-09 22:16:10 +02:00
parent 19171696c6
commit 3a2b718f09
7 changed files with 128 additions and 40 deletions

View File

@ -58,6 +58,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandPreferencesActi
import nodomain.freeyourgadget.gadgetbridge.devices.zetime.ZeTimePreferenceActivity;
import nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsPreferencesActivity;
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
import nodomain.freeyourgadget.gadgetbridge.service.devices.lenovo.watchxplus.WatchXPlusDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.util.AndroidUtils;
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
@ -90,6 +91,7 @@ public class SettingsActivity extends AbstractSettingsActivity {
Prefs prefs = GBApplication.getPrefs();
Preference pref = findPreference("notifications_generic");
pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
Intent enableIntent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
@ -209,6 +211,17 @@ public class SettingsActivity extends AbstractSettingsActivity {
});
pref = findPreference("watchxplus_button_BP_calibration");
pref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newVal) {
LOG.info(" uhaaaa ");
preference.setSummary("Calibrating, please wait... (if no result after 15s. re-run)");
GBApplication.deviceService().onSendConfiguration("BP_CAL");
return true;
}
});
final Preference unit = findPreference(PREF_MEASUREMENT_SYSTEM);
unit.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override

View File

@ -41,6 +41,8 @@ public final class WatchXPlusConstants extends LenovoWatchConstants {
public static final String PREF_IS_BP_CALIBRATED = "watchxplus_is_bp_calibrated";
public static final String PREF_BUTTON_REJECT = "watchxplus_button_reject";
public static final String PREF_SHAKE_REJECT = "watchxplus_shake_reject";
public static final String PREF_BP_CAL_LOW = "pref_wxp_bp_calibration_low";
public static final String PREF_BP_CAL_HIGH = "pref_wxp_bp_calibration_high";
// time format constants
@ -64,6 +66,7 @@ public final class WatchXPlusConstants extends LenovoWatchConstants {
public static final byte[] CMD_NOTIFICATION_CANCEL = new byte[]{0x03, 0x04};
public static final byte[] CMD_NOTIFICATION_SETTINGS = new byte[]{0x03, 0x02};
public static final byte[] CMD_DO_NOT_DISTURB_SETTINGS = new byte[]{0x03, 0x61};
public static final byte[] CMD_POWER_MODE = new byte[]{0x03, -0x7F}; //bArr[8] - 0 normal, 1 poser save, 2 green
public static final byte[] CMD_FITNESS_GOAL_SETTINGS = new byte[]{0x10, 0x02};
public static final byte[] CMD_DAY_STEPS_INFO = new byte[]{0x10, 0x03};
@ -77,10 +80,11 @@ public final class WatchXPlusConstants extends LenovoWatchConstants {
public static final byte[] RESP_DISCONNECT_REMIND = new byte[]{0x08, 0x00, 0x11};
public static final byte[] RESP_IS_BP_CALIBRATED = new byte[]{0x08, 0x05, 0x0B};
public static final byte[] RESP_BUTTON_WHILE_RING = new byte[]{0x04, 0x03, 0x03};
public static final byte[] RESP_BP_CALIBRATION = new byte[]{0x08, 0x05, 0x0C};
public static final byte[] RESP_AUTHORIZATION_TASK = new byte[]{0x01, 0x01, 0x05};
public static final byte[] RESP_DAY_STEPS_INDICATOR = new byte[]{0x08, 0x10, 0x03};
public static final byte[] RESP_HEARTRATE = new byte[]{-0x80, 0x15, 0x03};
public static final byte[] RESP_HEARTRATE = new byte[]{(byte) 0x80, 0x15, 0x03};
public static final byte[] RESP_DATA_COUNT = new byte[]{0x08, (byte)0xF0, 0x10};
public static final byte[] RESP_DATA_DETAILS = new byte[]{0x08, (byte)0xF0, 0x11};

View File

@ -29,6 +29,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.lenovo.watchxplus.WatchXPlusDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
import static nodomain.freeyourgadget.gadgetbridge.GBApplication.getContext;
@ -223,14 +224,6 @@ Prefs from device settings on main page
}
}
public static byte getBPCalibrationStatus(SharedPreferences sharedPrefs) {
String timeMode = sharedPrefs.getString(DeviceSettingsPreferenceConst.PREF_TIMEFORMAT, getContext().getString(R.string.p_timeformat_24h));
if (timeMode.equals(getContext().getString(R.string.p_timeformat_24h))) {
return WatchXPlusConstants.ARG_SET_TIMEMODE_24H;
} else {
return WatchXPlusConstants.ARG_SET_TIMEMODE_12H;
}
}
/*
Values from device specific settings page
*/

View File

@ -25,12 +25,18 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.CountDownTimer;
import android.os.Handler;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.IntRange;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.google.android.material.snackbar.Snackbar;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -50,6 +56,7 @@ import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.GBException;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
@ -64,7 +71,6 @@ import nodomain.freeyourgadget.gadgetbridge.entities.WatchXPlusActivitySample;
import nodomain.freeyourgadget.gadgetbridge.entities.WatchXPlusHealthActivityOverlay;
import nodomain.freeyourgadget.gadgetbridge.entities.WatchXPlusHealthActivityOverlayDao;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFindPhone;
import nodomain.freeyourgadget.gadgetbridge.externalevents.AlarmClockReceiver;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
@ -77,7 +83,6 @@ import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
@ -87,12 +92,13 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateA
import nodomain.freeyourgadget.gadgetbridge.service.devices.lenovo.operations.InitOperation;
import nodomain.freeyourgadget.gadgetbridge.util.AlarmUtils;
import nodomain.freeyourgadget.gadgetbridge.util.ArrayUtils;
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
protected static Prefs prefs = GBApplication.getPrefs();
private boolean needsAuth;
private int sequenceNumber = 0;
private boolean isCalibrationActive = false;
@ -568,6 +574,8 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
}
}
@Override
public void onSetCannedMessages(CannedMessagesSpec cannedMessagesSpec) {
@ -655,7 +663,6 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
@Override
public void onFindDevice(boolean start) {
}
@Override
@ -665,7 +672,7 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
@Override
public void onScreenshotReq() {
sendBloodPressureCalibration();
}
@Override
@ -707,11 +714,10 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
getDisconnectReminderStatus(builder);
break;
case DeviceSettingsPreferenceConst.PREF_TIMEFORMAT:
setTimeMode(builder, sharedPreferences);
setTimeFormat(builder, sharedPreferences);
break;
case WatchXPlusConstants.PREF_ALTITUDE:
LOG.info(" ALTITUDE: " + config);
case "BP_CAL":
sendBloodPressureCalibration();
break;
}
builder.queue(getQueue());
@ -739,18 +745,64 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
return this;
}
CoordinatorLayout coordinatorLayout;
// check status of blood pressure calibration
private WatchXPlusDeviceSupport sendBloodPressureCalibration() {
try {
int mLowP = prefs.getInt(WatchXPlusConstants.PREF_BP_CAL_LOW, 80);
int mHighP = prefs.getInt(WatchXPlusConstants.PREF_BP_CAL_HIGH, 130);
LOG.warn("Calibrating BP ... LowP=" + mLowP + " HighP="+mHighP);
GB.toast("Calibrating BP...", Toast.LENGTH_LONG, GB.INFO);
TransactionBuilder builder = performInitialized("bpCalibrate");
byte[] command = WatchXPlusConstants.CMD_BP_CALIBRATION;
byte mStart = 0x01;
byte[] bArr = new byte[5];
bArr[0] = (byte) mStart; // byte[08]
bArr[1] = (byte) (mHighP >> 8); // byte[09]
bArr[2] = (byte) mHighP; // byte[10]
bArr[3] = (byte) (mLowP >> 8); // byte[11]
bArr[4] = (byte) mLowP; // byte[12]
builder.write(getCharacteristic(WatchXPlusConstants.UUID_CHARACTERISTIC_WRITE),
buildCommand(command,
WatchXPlusConstants.TASK,
bArr));
builder.queue(getQueue()); } catch (IOException e) {
LOG.warn("Unable to send BP Calibration", e);
}
return this;
}
private void handleBloodPressureCalibrationStatus(byte[] value) {
if (Conversion.calculateHigh(value[8]) != 0) {
if (Conversion.fromByteArr16(value[8]) != 0) {
WatchXPlusDeviceCoordinator.isBPCalibrated = false;
} else {
WatchXPlusDeviceCoordinator.isBPCalibrated = true;
}
}
private void handleBloodPressureCalibrationResult(byte[] value) {
if (Conversion.fromByteArr16(value[8]) != 0x00) {
WatchXPlusDeviceCoordinator.isBPCalibrated = false;
GB.toast("Calibrating BP fail", Toast.LENGTH_LONG, GB.ERROR);
} else {
WatchXPlusDeviceCoordinator.isBPCalibrated = true;
int high = Conversion.fromByteArr16(value[9], value[10]);
int low = Conversion.fromByteArr16(value[11], value[12]);
GB.toast("OK. Measured Low:"+low+" high:"+high, Toast.LENGTH_LONG, GB.INFO);
}
}
// end check status of blood pressure calibration
private void requestBloodPressureMeasurement() {
if (!WatchXPlusDeviceCoordinator.isBPCalibrated) {
LOG.warn("BP is NOT calibrated");
GB.toast("BP is not calibrated", Toast.LENGTH_LONG, GB.WARN);
return;
}
try {
@ -836,6 +888,8 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
handleTime(value);
} else if (ArrayUtils.equals(value, WatchXPlusConstants.RESP_IS_BP_CALIBRATED, 5)) {
handleBloodPressureCalibrationStatus(value);
} else if (ArrayUtils.equals(value, WatchXPlusConstants.RESP_BP_CALIBRATION, 5)) {
handleBloodPressureCalibrationResult(value);
} else if (ArrayUtils.equals(value, WatchXPlusConstants.RESP_BUTTON_INDICATOR, 5)) {
this.onReverseFindDevice(true);
// It looks like WatchXPlus doesn't send this action
@ -874,7 +928,7 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
return true;
} else if (WatchXPlusConstants.UUID_CHARACTERISTIC_DATABASE_READ.equals(characteristicUUID)) {
LOG.info(" Value change for characteristic DATABASE: " + characteristicUUID + " value " + value);
handleContentDataChunk(value);
return true;
} else {
@ -1123,12 +1177,13 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
if (value.length < 11) {
LOG.info(" BP Measure started. Waiting for result");
GB.toast("BP Measure started. Waiting for result...", Toast.LENGTH_LONG, GB.INFO);
} else {
LOG.info(" Received BP live data");
int high = Conversion.fromByteArr16(value[8], value[9]);
int low = Conversion.fromByteArr16(value[10], value[11]);
int timestamp = Conversion.fromByteArr16(value[12], value[13], value[14], value[15]);
GB.toast("Calculated BP data: low: " + low + ", high: " + high, Toast.LENGTH_LONG, GB.INFO);
LOG.info(" Calculated BP data: timestamp: " + timestamp + ", high: " + high + ", low: " + low);
}
}
@ -1341,7 +1396,7 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
SharedPreferences sharedPreferences = GBApplication.getDeviceSpecificSharedPrefs(this.getDevice().getAddress());
this.setHeadsUpScreen(transaction, sharedPreferences); // lift wirst to screen on
this.setDisconnectReminder(transaction, sharedPreferences); // disconnect reminder
this.setTimeMode(transaction, sharedPreferences); // set time mode 12/24h
this.setTimeFormat(transaction, sharedPreferences); // set time mode 12/24h
this.setAltitude(transaction); // set altitude calibration
}
@ -1437,7 +1492,7 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
}
// set time format
private WatchXPlusDeviceSupport setTimeMode(TransactionBuilder transactionBuilder, byte timeMode) {
private WatchXPlusDeviceSupport setTimeFormat(TransactionBuilder transactionBuilder, byte timeMode) {
byte[] bArr = new byte[2];
bArr[0] = 0x01; //byte[08] language - force to English language
bArr[1] = timeMode; //byte[09] time
@ -1445,7 +1500,6 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
buildCommand(WatchXPlusConstants.CMD_TIME_LANGUAGE,
WatchXPlusConstants.WRITE_VALUE,
bArr));
//LOG.info(" setTimeMode: " + bArr);
return this;
}
@ -1470,8 +1524,8 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
return this;
}
private WatchXPlusDeviceSupport setTimeMode(TransactionBuilder transactionBuilder, SharedPreferences sharedPreferences) {
return this.setTimeMode(transactionBuilder,
private WatchXPlusDeviceSupport setTimeFormat(TransactionBuilder transactionBuilder, SharedPreferences sharedPreferences) {
return this.setTimeFormat(transactionBuilder,
WatchXPlusDeviceCoordinator.getTimeMode(sharedPreferences));
}
@ -1501,6 +1555,8 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
}
}
private static class Conversion {
static byte toBcd8(@IntRange(from = 0, to = 99) int value) {
int high = (value / 10) << 4;
@ -1518,7 +1574,7 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
return new byte[]{(byte) (value >> 8), (byte) value};
}
static int fromByteArr16(byte... value) {
static int fromByteArr16(byte... value) { // equals calculateHigh
int intValue = 0;
for (int i2 = 0; i2 < value.length; i2++) {
intValue += (value[i2] & 255) << (((value.length - 1) - i2) * 8);
@ -1542,15 +1598,5 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
}
return i2;
}
static int calculateHigh(byte... bArr) {
int i = 0;
int i2 = 0;
while (i < bArr.length) {
i2 += (bArr[i] & 255) << (((bArr.length - 1) - i) * 8);
i++;
}
return i2;
}
}
}

View File

@ -289,8 +289,11 @@
<string name="pref_wxp_title_altitude">Калибриране на височина</string>
<string name="pref_wxp_title_repeat_on_call">Повтори известия за звънене</string>
<string name="pref_wxp_title_repeat_on_call_summary">Възможни стойности min=0, max=10</string>
<string name="prefs_wxp_continious">Известие докато звъни</string>
<string name="prefs_wxp_continious">Известявай докато телефона звъни</string>
<string name="pref_wxp_title_reject_summary">Изкл. - игнорира, Вкл. - отказ</string>
<string name="wxp_bp_calibration_prefs">Калибриране на кръвно налягане</string>
<string name="pref_wxp_bp_calibration_low">Кръвно налягане DIASTOLIC (долна)</string>
<string name="pref_wxp_bp_calibration_high">Кръвно налягане SYSTOLIC (горна)</string>
<string name="prefs_wxp_reject">Бутона игнорира/отказва повикване</string>
<string name="pref_wxp_title_shake_reject_summary">Дублира действието на бутона</string>
<string name="prefs_wxp_shake_reject">Разклащането игнорира/отказва повикване</string>

View File

@ -199,6 +199,11 @@
<string name="prefs_wxp_reject">Button ignore/reject call</string>
<string name="pref_wxp_title_shake_reject_summary">Duplicates watch button action</string>
<string name="prefs_wxp_shake_reject">Shake wrist ignore/reject call</string>
<string name="wxp_bp_calibration_prefs">Blood Pressure calibration</string>
<string name="pref_wxp_bp_calibration_low">Blood Pressure DIASTOLIC (low)</string>
<string name="pref_wxp_bp_calibration_high">Blood Pressure SYSTOLIC (high)</string>
<string name="prefs_wxp_button_bp_calibration">Begin calibration</string>
<string name="prefs_wxp_button_bp_calibration_sum">Press here to begin calibration</string>
<string name="pref_header_wxp_calibration">WatchXPlus calibration</string>
<!-- Makibes HR3 Preferences -->
<string name="preferences_makibes_hr3_settings">Makibes HR3 settings</string>

View File

@ -620,6 +620,30 @@
android:key="watchxplus_altitude"
android:title="@string/pref_wxp_title_altitude"/>
<PreferenceScreen
android:key="wxp_bp_calibration"
android:title="@string/wxp_bp_calibration_prefs">
<EditTextPreference
android:inputType="number"
android:key="wxp_bp_calibration_low"
android:defaultValue="80"
android:title="@string/pref_wxp_bp_calibration_low"
android:summary="@string/pref_rtl_max_line_length_summary"/>
<EditTextPreference
android:inputType="number"
android:key="wxp_bp_calibration_high"
android:defaultValue="130"
android:title="@string/pref_wxp_bp_calibration_high"
android:summary="@string/pref_rtl_max_line_length_summary"/>
<CheckBoxPreference
android:layout="@layout/preference_checkbox"
android:defaultValue="false"
android:key="watchxplus_button_BP_calibration"
android:summary="@string/prefs_wxp_button_bp_calibration_sum"
android:title="@string/prefs_wxp_button_bp_calibration" />
</PreferenceScreen>
</PreferenceCategory>
</PreferenceScreen>