mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2025-02-18 05:17:08 +01:00
Retrieve steps count
Tried to set weather, but without success Handle ACK response Enabled alarms
This commit is contained in:
parent
290a90ec0e
commit
34d9bccb86
@ -54,7 +54,9 @@ public final class WatchXPlusConstants {
|
||||
public static final byte[] CMD_AUTHORIZATION_TASK = new byte[]{0x01, 0x05};
|
||||
public static final byte[] CMD_TIME_SETTINGS = new byte[]{0x01, 0x08};
|
||||
public static final byte[] CMD_ALARM_SETTINGS = new byte[]{0x01, 0x0A};
|
||||
public static final byte[] CMD_WEATHER_SET = new byte[]{0x01, 0x10};
|
||||
public static final byte[] CMD_BATTERY_INFO = new byte[]{0x01, 0x14};
|
||||
public static final byte[] CMD_HEARTRATE_INFO = new byte[]{0x15, 0x03};
|
||||
|
||||
public static final byte[] CMD_NOTIFICATION_TASK = new byte[]{0x03, 0x01};
|
||||
public static final byte[] CMD_NOTIFICATION_TEXT_TASK = new byte[]{0x03, 0x06};
|
||||
@ -65,15 +67,18 @@ public final class WatchXPlusConstants {
|
||||
public static final byte[] CMD_DO_NOT_DISTURB_SETTINGS = new byte[]{0x03, 0x61};
|
||||
|
||||
public static final byte[] CMD_FITNESS_GOAL_SETTINGS = new byte[]{0x10, 0x02};
|
||||
public static final byte[] CMD_DAY_STEPS_INFO = new byte[]{0x10, 0x03};
|
||||
|
||||
public static final byte[] RESP_AUTHORIZATION_TASK = new byte[]{0x01, 0x01, 0x05};
|
||||
public static final byte[] RESP_BUTTON_INDICATOR = new byte[]{0x04, 0x03, 0x11};
|
||||
public static final byte[] RESP_ALARM_INDICATOR = new byte[]{-0x80, 0x01, 0x0A};
|
||||
public static final byte[] RESP_DAY_STEPS_INDICATOR = new byte[]{0x08, 0x10, 0x03};
|
||||
public static final byte[] RESP_HEARTRATE = new byte[]{0x08, 0x15, 0x02};
|
||||
|
||||
public static final byte[] RESP_FIRMWARE_INFO = new byte[]{0x08, 0x01, 0x02};
|
||||
public static final byte[] RESP_TIME_SETTINGS = new byte[]{0x08, 0x01, 0x08};
|
||||
public static final byte[] RESP_BATTERY_INFO = new byte[]{0x08, 0x01, 0x14};
|
||||
public static final byte[] RESP_NOTIFICATION_SETTINGS = new byte[]{0x08, 0x03, 0x02};
|
||||
public static final byte[] RESP_NOTIFICATION_SETTINGS = new byte[]{0x01, 0x03, 0x02};
|
||||
|
||||
public static final String ACTION_ENABLE = "action.watch9.enable";
|
||||
|
||||
|
@ -8,17 +8,16 @@ import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.ParcelUuid;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.watchxplus.WatchXPlusConstants;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.watchxplus.WatchXPlusPairingActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
@ -76,7 +75,7 @@ public class WatchXPlusDeviceCoordinator extends AbstractDeviceCoordinator {
|
||||
|
||||
@Override
|
||||
public boolean supportsActivityDataFetching() {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -101,7 +100,7 @@ public class WatchXPlusDeviceCoordinator extends AbstractDeviceCoordinator {
|
||||
|
||||
@Override
|
||||
public int getAlarmSlotCount() {
|
||||
return 0;
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -111,7 +110,7 @@ public class WatchXPlusDeviceCoordinator extends AbstractDeviceCoordinator {
|
||||
|
||||
@Override
|
||||
public boolean supportsHeartRateMeasurement(GBDevice device) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -141,7 +140,7 @@ public class WatchXPlusDeviceCoordinator extends AbstractDeviceCoordinator {
|
||||
|
||||
@Override
|
||||
public boolean supportsWeather() {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -478,6 +478,22 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
@Override
|
||||
public void onFetchRecordedData(int dataTypes) {
|
||||
|
||||
TransactionBuilder builder = null;
|
||||
try {
|
||||
builder = performInitialized("fetchData");
|
||||
|
||||
builder.write(getCharacteristic(WatchXPlusConstants.UUID_CHARACTERISTIC_WRITE),
|
||||
buildCommand(WatchXPlusConstants.CMD_DAY_STEPS_INFO,
|
||||
WatchXPlusConstants.READ_VALUE));
|
||||
// TODO: Watch does not return heart rate data after this command. Check why
|
||||
// builder.write(getCharacteristic(WatchXPlusConstants.UUID_CHARACTERISTIC_WRITE),
|
||||
// buildCommand(WatchXPlusConstants.CMD_HEARTRATE_INFO,
|
||||
// WatchXPlusConstants.READ_VALUE));
|
||||
|
||||
performImmediately(builder);
|
||||
} catch (IOException e) {
|
||||
LOG.warn("Unable to retrieve recorded data", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -558,7 +574,26 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
|
||||
@Override
|
||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized("setWeather");
|
||||
|
||||
byte[] command = WatchXPlusConstants.CMD_WEATHER_SET;
|
||||
byte[] weatherInfo = new byte[5];
|
||||
|
||||
// bArr[8] = (byte) (this.mWeatherType >> 8);
|
||||
// bArr[9] = (byte) this.mWeatherType;
|
||||
// bArr[10] = (byte) this.mLowTemp;
|
||||
// bArr[11] = (byte) this.mHighTemp;
|
||||
// bArr[12] = (byte) this.mCurrentTemp;
|
||||
|
||||
builder.write(getCharacteristic(WatchXPlusConstants.UUID_CHARACTERISTIC_WRITE),
|
||||
buildCommand(command,
|
||||
WatchXPlusConstants.KEEP_ALIVE,
|
||||
weatherInfo));
|
||||
performImmediately(builder);
|
||||
} catch (IOException e) {
|
||||
LOG.warn("Unable to set time", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -576,23 +611,71 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
} else if (ArrayUtils.equals(value, WatchXPlusConstants.RESP_TIME_SETTINGS, 5)) {
|
||||
handleTime(value);
|
||||
} else if (ArrayUtils.equals(value, WatchXPlusConstants.RESP_BUTTON_INDICATOR, 5)) {
|
||||
LOG.info("Unhandled action: Button pressed");
|
||||
// It looks like WatchXPlus doesn't send this action
|
||||
LOG.info(" Unhandled action: Button pressed");
|
||||
} else if (ArrayUtils.equals(value, WatchXPlusConstants.RESP_ALARM_INDICATOR, 5)) {
|
||||
LOG.info("Alarm active: id=" + value[8]);
|
||||
LOG.info(" Alarm active: id=" + value[8]);
|
||||
} else if (isCalibrationActive && value.length == 7 && value[4] == ACK_CALIBRATION) {
|
||||
setTime(BLETypeConversions.createCalendar());
|
||||
isCalibrationActive = false;
|
||||
} else if (ArrayUtils.equals(value, WatchXPlusConstants.RESP_DAY_STEPS_INDICATOR, 5)) {
|
||||
handleStepsInfo(value);
|
||||
} else if (ArrayUtils.equals(value, WatchXPlusConstants.RESP_HEARTRATE, 5)) {
|
||||
LOG.info(" Received Heart rate history");
|
||||
} else if (value.length == 7 && value[5] == 0) {
|
||||
// Not sure if that's necessary
|
||||
handleAck();
|
||||
} else if (ArrayUtils.equals(value, WatchXPlusConstants.RESP_NOTIFICATION_SETTINGS, 5)) {
|
||||
LOG.info(" Received notification settings status");
|
||||
} else {
|
||||
LOG.info(" Unhandled value change for characteristic: " + characteristicUUID);
|
||||
logMessageContent(characteristic.getValue());
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
LOG.info("Unhandled characteristic changed: " + characteristicUUID);
|
||||
LOG.info(" Unhandled characteristic changed: " + characteristicUUID);
|
||||
logMessageContent(characteristic.getValue());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void handleAck() {
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized("handleAck");
|
||||
|
||||
builder.write(getCharacteristic(WatchXPlusConstants.UUID_CHARACTERISTIC_WRITE),
|
||||
// TODO: Below value is ACK status. Find out which value is correct
|
||||
buildCommand((byte)0x00));
|
||||
performImmediately(builder);
|
||||
} catch (IOException e) {
|
||||
LOG.warn("Unable to response to ACK", e);
|
||||
}
|
||||
}
|
||||
|
||||
// This is only for ACK response
|
||||
private byte[] buildCommand(byte action) {
|
||||
byte[] result = new byte[7];
|
||||
System.arraycopy(WatchXPlusConstants.CMD_HEADER, 0, result, 0, 5);
|
||||
|
||||
result[2] = (byte) (result.length + 1);
|
||||
result[3] = WatchXPlusConstants.REQUEST;
|
||||
result[4] = (byte) sequenceNumber++;
|
||||
result[5] = action;
|
||||
result[result.length - 1] = calculateChecksum(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void handleStepsInfo(byte[] value) {
|
||||
int steps = Conversion.fromByteArr16(value[8], value[9]);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug(" Received steps count: " + steps);
|
||||
}
|
||||
// TODO: save steps to DB
|
||||
}
|
||||
|
||||
private byte[] buildCommand(byte[] command, byte action) {
|
||||
return buildCommand(command, action, null);
|
||||
}
|
||||
@ -656,6 +739,13 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
static byte[] toByteArr16(int value) {
|
||||
return new byte[]{(byte) (value >> 8), (byte) value};
|
||||
}
|
||||
static int fromByteArr16(byte... value) {
|
||||
int intValue = 0;
|
||||
for (int i2 = 0; i2 < value.length; i2++) {
|
||||
intValue += (value[i2] & 255) << (((value.length - 1) - i2) * 8);
|
||||
}
|
||||
return intValue;
|
||||
}
|
||||
|
||||
static byte[] toByteArr32(int value) {
|
||||
return new byte[]{(byte) (value >> 24),
|
||||
|
Loading…
x
Reference in New Issue
Block a user