mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2025-01-10 17:11:56 +01:00
Xiaomi-protobuf: Persist heart pulse samples
This commit is contained in:
parent
95b9009318
commit
69847c19ff
@ -54,7 +54,7 @@ public class GBDaoGenerator {
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
final Schema schema = new Schema(90, MAIN_PACKAGE + ".entities");
|
||||
final Schema schema = new Schema(91, MAIN_PACKAGE + ".entities");
|
||||
|
||||
Entity userAttributes = addUserAttributes(schema);
|
||||
Entity user = addUserInfo(schema, userAttributes);
|
||||
@ -81,6 +81,7 @@ public class GBDaoGenerator {
|
||||
addHuamiSleepRespiratoryRateSample(schema, user, device);
|
||||
addXiaomiActivitySample(schema, user, device);
|
||||
addXiaomiSleepTimeSamples(schema, user, device);
|
||||
addHeartPulseSamples(schema, user, device);
|
||||
addXiaomiSleepStageSamples(schema, user, device);
|
||||
addXiaomiManualSamples(schema, user, device);
|
||||
addXiaomiDailySummarySamples(schema, user, device);
|
||||
@ -410,6 +411,12 @@ public class GBDaoGenerator {
|
||||
return sample;
|
||||
}
|
||||
|
||||
private static Entity addHeartPulseSamples(Schema schema, Entity user, Entity device) {
|
||||
Entity sample = addEntity(schema, "HeartPulseSample");
|
||||
addCommonTimeSampleProperties("AbstractTimeSample", sample, user, device);
|
||||
return sample;
|
||||
}
|
||||
|
||||
private static Entity addXiaomiSleepStageSamples(Schema schema, Entity user, Entity device) {
|
||||
Entity sample = addEntity(schema, "XiaomiSleepStageSample");
|
||||
addCommonTimeSampleProperties("AbstractTimeSample", sample, user, device);
|
||||
|
@ -0,0 +1,55 @@
|
||||
/* Copyright (C) 2024 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 <https://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import de.greenrobot.dao.AbstractDao;
|
||||
import de.greenrobot.dao.Property;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HeartPulseSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HeartPulseSampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
|
||||
public class HeartPulseSampleProvider extends AbstractTimeSampleProvider<HeartPulseSample> {
|
||||
public HeartPulseSampleProvider(final GBDevice device, final DaoSession session) {
|
||||
super(device, session);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public AbstractDao<HeartPulseSample, ?> getSampleDao() {
|
||||
return getSession().getHeartPulseSampleDao();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Property getTimestampSampleProperty() {
|
||||
return HeartPulseSampleDao.Properties.Timestamp;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Property getDeviceIdentifierSampleProperty() {
|
||||
return HeartPulseSampleDao.Properties.DeviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HeartPulseSample createSample() {
|
||||
return new HeartPulseSample();
|
||||
}
|
||||
}
|
@ -30,10 +30,12 @@ import java.util.List;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.HeartPulseSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.xiaomi.XiaomiSleepStageSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.xiaomi.XiaomiSleepTimeSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HeartPulseSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.User;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.XiaomiSleepStageSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.XiaomiSleepTimeSample;
|
||||
@ -140,6 +142,7 @@ public class SleepDetailsParser extends XiaomiActivityParser {
|
||||
}
|
||||
|
||||
final List<XiaomiSleepStageSample> stages = new ArrayList<>();
|
||||
final List<HeartPulseSample> heartPulseSamples = new ArrayList<>();
|
||||
LOG.debug("Sleep stage packets from offset {}", Integer.toHexString(buf.position()));
|
||||
|
||||
// Do not crash if we face a buffer underflow, as the next parsing is not 100% fool-proof,
|
||||
@ -181,7 +184,16 @@ public class SleepDetailsParser extends XiaomiActivityParser {
|
||||
|
||||
final ByteBuffer dataBuf = ByteBuffer.wrap(data).order(ByteOrder.BIG_ENDIAN);
|
||||
|
||||
if (type == 16) {
|
||||
if (type == 1) {
|
||||
long timestampAcc = ts;
|
||||
while (dataBuf.position() < dataBuf.limit()) {
|
||||
final int delta = dataBuf.get() & 0xff;
|
||||
final HeartPulseSample heartPulseSample = new HeartPulseSample();
|
||||
heartPulseSample.setTimestamp(timestampAcc + delta);
|
||||
heartPulseSamples.add(heartPulseSample);
|
||||
timestampAcc += delta;
|
||||
}
|
||||
} else if (type == 16) {
|
||||
final int data_0 = dataBuf.get() & 0xFF;
|
||||
final int sleep_index = data_0 >> 4;
|
||||
final int wake_count = data_0 & 0x0F;
|
||||
@ -243,6 +255,8 @@ public class SleepDetailsParser extends XiaomiActivityParser {
|
||||
summaries.add(sample);
|
||||
}
|
||||
|
||||
boolean persistSuccess = !stagesParseFailed;
|
||||
|
||||
// save all the samples that we got
|
||||
try (DBHandler handler = GBApplication.acquireDB()) {
|
||||
final DaoSession session = handler.getDaoSession();
|
||||
@ -271,7 +285,7 @@ public class SleepDetailsParser extends XiaomiActivityParser {
|
||||
} catch (final Exception e) {
|
||||
GB.toast(support.getContext(), "Error saving sleep sample", Toast.LENGTH_LONG, GB.ERROR);
|
||||
LOG.error("Error saving sleep sample", e);
|
||||
return false;
|
||||
persistSuccess = false;
|
||||
}
|
||||
|
||||
if (!stagesParseFailed && !stages.isEmpty()) {
|
||||
@ -295,11 +309,32 @@ public class SleepDetailsParser extends XiaomiActivityParser {
|
||||
} catch (final Exception e) {
|
||||
GB.toast(support.getContext(), "Error saving sleep stage samples", Toast.LENGTH_LONG, GB.ERROR);
|
||||
LOG.error("Error saving sleep stage samples", e);
|
||||
return false;
|
||||
persistSuccess = false;
|
||||
}
|
||||
}
|
||||
|
||||
return !stagesParseFailed;
|
||||
// Save the heart pulse samples
|
||||
try (DBHandler handler = GBApplication.acquireDB()) {
|
||||
final DaoSession session = handler.getDaoSession();
|
||||
final GBDevice gbDevice = support.getDevice();
|
||||
final Device device = DBHelper.getDevice(gbDevice, session);
|
||||
final User user = DBHelper.getUser(session);
|
||||
|
||||
final HeartPulseSampleProvider sampleProvider = new HeartPulseSampleProvider(gbDevice, session);
|
||||
|
||||
for (final HeartPulseSample stageSample : heartPulseSamples) {
|
||||
stageSample.setDevice(device);
|
||||
stageSample.setUser(user);
|
||||
}
|
||||
|
||||
sampleProvider.addSamples(heartPulseSamples);
|
||||
} catch (final Exception e) {
|
||||
GB.toast(support.getContext(), "Error saving heart pulse samples", Toast.LENGTH_LONG, GB.ERROR);
|
||||
LOG.error("Error saving heart pulse samples", e);
|
||||
persistSuccess = false;
|
||||
}
|
||||
|
||||
return persistSuccess;
|
||||
}
|
||||
|
||||
private static boolean readStagePacketHeader(final ByteBuffer buffer) {
|
||||
|
Loading…
Reference in New Issue
Block a user