1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-12-24 09:35:50 +01:00

TimeSampleProvider: Add getLatestSample(until)

This commit is contained in:
José Rebelo 2024-12-14 14:16:02 +00:00
parent 66457a76f9
commit 4374a61c40
21 changed files with 215 additions and 144 deletions

View File

@ -128,6 +128,29 @@ public abstract class AbstractSampleProvider<T extends AbstractActivitySample> i
return sample;
}
@Nullable
@Override
public T getLatestActivitySample(final int until) {
QueryBuilder<T> qb = getSampleDao().queryBuilder();
Device dbDevice = DBHelper.findDevice(getDevice(), getSession());
if (dbDevice == null) {
// no device, no sample
return null;
}
Property deviceProperty = getDeviceIdentifierSampleProperty();
Property timestampProperty = getTimestampSampleProperty();
qb.where(timestampProperty.le(until))
.where(deviceProperty.eq(dbDevice.getId()))
.orderDesc(timestampProperty).limit(1);
List<T> samples = qb.build().list();
if (samples.isEmpty()) {
return null;
}
T sample = samples.get(0);
sample.setProvider(this);
return sample;
}
@Nullable
@Override
public T getFirstActivitySample() {

View File

@ -88,6 +88,13 @@ public abstract class AbstractSampleToTimeSampleProvider<T extends TimeSample, S
return convertSample(latestSample);
}
@Nullable
@Override
public T getLatestSample(final long until) {
final S latestSample = mSampleProvider.getLatestActivitySample((int) (until / 1000L));
return convertSample(latestSample);
}
@Nullable
@Override
public T getFirstSample() {

View File

@ -100,6 +100,26 @@ public abstract class AbstractTimeSampleProvider<T extends AbstractTimeSample> i
return samples.get(0);
}
@Nullable
@Override
public T getLatestSample(final long until) {
final QueryBuilder<T> qb = getSampleDao().queryBuilder();
final Device dbDevice = DBHelper.findDevice(getDevice(), getSession());
if (dbDevice == null) {
// no device, no sample
return null;
}
final Property deviceProperty = getDeviceIdentifierSampleProperty();
qb.where(getTimestampSampleProperty().le(until))
.where(deviceProperty.eq(dbDevice.getId()))
.orderDesc(getTimestampSampleProperty()).limit(1);
final List<T> samples = qb.build().list();
if (samples.isEmpty()) {
return null;
}
return samples.get(0);
}
@Nullable
public T getLastSampleBefore(final long timestampTo) {
final Device dbDevice = DBHelper.findDevice(getDevice(), getSession());

View File

@ -105,6 +105,13 @@ public interface SampleProvider<T extends AbstractActivitySample> {
@Nullable
T getLatestActivitySample();
/**
* Returns the activity sample with the highest timestamp, until a limit (inclusive). or null if none
* @return the latest sample or null
*/
@Nullable
T getLatestActivitySample(int until);
/**
* Returns the activity sample with the oldest timestamp or null if none
* @return the oldest sample or null

View File

@ -79,6 +79,16 @@ public interface TimeSampleProvider<T extends TimeSample> {
@Nullable
T getLatestSample();
/**
* Returns the sample with the highest timestamp until a limit, or null if none.
*
* @param until maximum timestamp of the sample, inclusive
*
* @return the latest sample, or null if none is found.
*/
@Nullable
T getLatestSample(long until);
/**
* Returns the sample with the oldest timestamp, or null if none.
*

View File

@ -99,6 +99,12 @@ public class UnknownDeviceCoordinator extends AbstractDeviceCoordinator {
return null;
}
@Nullable
@Override
public AbstractActivitySample getLatestActivitySample(final int until) {
return null;
}
@Nullable
@Override
public AbstractActivitySample getFirstActivitySample() {

View File

@ -7,4 +7,9 @@ import nodomain.freeyourgadget.gadgetbridge.model.Vo2MaxSample;
public interface Vo2MaxSampleProvider<T extends Vo2MaxSample> extends TimeSampleProvider<T> {
@Nullable
T getLatestSample(Vo2MaxSample.Type type, long until);
@Nullable
default T getLatestSample(long until) {
return getLatestSample(Vo2MaxSample.Type.ANY, until);
}
}

View File

@ -8,27 +8,19 @@ import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import de.greenrobot.dao.Property;
import de.greenrobot.dao.query.QueryBuilder;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiActivitySample;
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiActivitySampleDao;
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiDictData;
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiDictDataDao;
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiDictDataValues;
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiDictDataValuesDao;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.TemperatureSample;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.p2p.HuaweiP2PDataDictionarySyncService;
public class HuaweiTemperatureSampleProvider implements TimeSampleProvider<TemperatureSample> {
@ -159,6 +151,37 @@ public class HuaweiTemperatureSampleProvider implements TimeSampleProvider<Tempe
return new HuaweiTemperatureSample(valuesData.get(0).getHuaweiDictData().getStartTimestamp(), (float) conv2Double(valuesData.get(0).getValue()));
}
@Nullable
@Override
public TemperatureSample getLatestSample(final long until) {
Long userId = DBHelper.getUser(this.session).getId();
Long deviceId = DBHelper.getDevice(this.device, this.session).getId();
if (deviceId == null || userId == null)
return null;
QueryBuilder<HuaweiDictData> qb = this.session.getHuaweiDictDataDao().queryBuilder();
qb.where(HuaweiDictDataDao.Properties.StartTimestamp.le(until))
.where(HuaweiDictDataDao.Properties.DeviceId.eq(deviceId))
.where(HuaweiDictDataDao.Properties.UserId.eq(userId))
.where(HuaweiDictDataDao.Properties.DictClass.eq(HuaweiDictTypes.SKIN_TEMPERATURE_CLASS));
qb.orderDesc(HuaweiDictDataDao.Properties.StartTimestamp).limit(1);
final List<HuaweiDictData> data = qb.build().list();
if (data.isEmpty())
return null;
QueryBuilder<HuaweiDictDataValues> qbv = this.session.getHuaweiDictDataValuesDao().queryBuilder();
qbv.where(HuaweiDictDataValuesDao.Properties.DictType.eq(HuaweiDictTypes.SKIN_TEMPERATURE_VALUE)).where(HuaweiDictDataValuesDao.Properties.Tag.eq(10)).where(HuaweiDictDataValuesDao.Properties.DictId.eq(data.get(0).getDictId()));
final List<HuaweiDictDataValues> valuesData = qbv.build().list();
if (valuesData.isEmpty())
return null;
return new HuaweiTemperatureSample(valuesData.get(0).getHuaweiDictData().getStartTimestamp(), (float) conv2Double(valuesData.get(0).getValue()));
}
@Nullable
@Override
public TemperatureSample getFirstSample() {

View File

@ -0,0 +1,48 @@
/* 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.test.samples;
import androidx.annotation.Nullable;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.model.TimeSample;
public abstract class AbstractTestSampleProvider<S extends TimeSample> implements TimeSampleProvider<S> {
@Nullable
@Override
public S getLatestSample(final long until) {
final List<S> allSamples = getAllSamples(until - 60, until);
return !allSamples.isEmpty() ? allSamples.get(allSamples.size() - 1) : null;
}
@Override
public void addSample(final S timeSample) {
throw new UnsupportedOperationException("read-only sample provider");
}
@Override
public void addSamples(final List<S> timeSamples) {
throw new UnsupportedOperationException("read-only sample provider");
}
@Override
public S createSample() {
throw new UnsupportedOperationException("read-only sample provider");
}
}

View File

@ -22,11 +22,10 @@ import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.test.TestDeviceRand;
import nodomain.freeyourgadget.gadgetbridge.model.BodyEnergySample;
public class TestBodyEnergySampleProvider implements TimeSampleProvider<BodyEnergySample> {
public class TestBodyEnergySampleProvider extends AbstractTestSampleProvider<BodyEnergySample> {
@NonNull
@Override
public List<BodyEnergySample> getAllSamples(final long timestampFrom, final long timestampTo) {
@ -39,21 +38,6 @@ public class TestBodyEnergySampleProvider implements TimeSampleProvider<BodyEner
return samples;
}
@Override
public void addSample(final BodyEnergySample timeSample) {
throw new UnsupportedOperationException("read-only sample provider");
}
@Override
public void addSamples(final List<BodyEnergySample> timeSamples) {
throw new UnsupportedOperationException("read-only sample provider");
}
@Override
public BodyEnergySample createSample() {
throw new UnsupportedOperationException("read-only sample provider");
}
@Nullable
@Override
public BodyEnergySample getLatestSample() {

View File

@ -22,11 +22,10 @@ import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.test.TestDeviceRand;
import nodomain.freeyourgadget.gadgetbridge.model.HrvSummarySample;
public class TestHrvSummarySampleProvider implements TimeSampleProvider<HrvSummarySample> {
public class TestHrvSummarySampleProvider extends AbstractTestSampleProvider<HrvSummarySample> {
@NonNull
@Override
public List<HrvSummarySample> getAllSamples(final long timestampFrom, final long timestampTo) {
@ -39,21 +38,6 @@ public class TestHrvSummarySampleProvider implements TimeSampleProvider<HrvSumma
return samples;
}
@Override
public void addSample(final HrvSummarySample timeSample) {
throw new UnsupportedOperationException("read-only sample provider");
}
@Override
public void addSamples(final List<HrvSummarySample> timeSamples) {
throw new UnsupportedOperationException("read-only sample provider");
}
@Override
public HrvSummarySample createSample() {
throw new UnsupportedOperationException("read-only sample provider");
}
@Nullable
@Override
public HrvSummarySample getLatestSample() {

View File

@ -22,11 +22,10 @@ import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.test.TestDeviceRand;
import nodomain.freeyourgadget.gadgetbridge.model.HrvValueSample;
public class TestHrvValueSampleProvider implements TimeSampleProvider<HrvValueSample> {
public class TestHrvValueSampleProvider extends AbstractTestSampleProvider<HrvValueSample> {
@NonNull
@Override
public List<HrvValueSample> getAllSamples(final long timestampFrom, final long timestampTo) {
@ -42,21 +41,6 @@ public class TestHrvValueSampleProvider implements TimeSampleProvider<HrvValueSa
return samples;
}
@Override
public void addSample(final HrvValueSample timeSample) {
throw new UnsupportedOperationException("read-only sample provider");
}
@Override
public void addSamples(final List<HrvValueSample> timeSamples) {
throw new UnsupportedOperationException("read-only sample provider");
}
@Override
public HrvValueSample createSample() {
throw new UnsupportedOperationException("read-only sample provider");
}
@Nullable
@Override
public HrvValueSample getLatestSample() {

View File

@ -22,11 +22,10 @@ import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.test.TestDeviceRand;
import nodomain.freeyourgadget.gadgetbridge.model.PaiSample;
public class TestPaiSampleProvider implements TimeSampleProvider<PaiSample> {
public class TestPaiSampleProvider extends AbstractTestSampleProvider<PaiSample> {
@NonNull
@Override
public List<PaiSample> getAllSamples(final long timestampFrom, final long timestampTo) {
@ -56,21 +55,6 @@ public class TestPaiSampleProvider implements TimeSampleProvider<PaiSample> {
return samples;
}
@Override
public void addSample(final PaiSample timeSample) {
throw new UnsupportedOperationException("read-only sample provider");
}
@Override
public void addSamples(final List<PaiSample> timeSamples) {
throw new UnsupportedOperationException("read-only sample provider");
}
@Override
public PaiSample createSample() {
throw new UnsupportedOperationException("read-only sample provider");
}
@Nullable
@Override
public PaiSample getLatestSample() {

View File

@ -22,11 +22,10 @@ import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.test.TestDeviceRand;
import nodomain.freeyourgadget.gadgetbridge.model.RespiratoryRateSample;
public class TestRespiratoryRateSampleProvider implements TimeSampleProvider<RespiratoryRateSample> {
public class TestRespiratoryRateSampleProvider extends AbstractTestSampleProvider<RespiratoryRateSample> {
@NonNull
@Override
public List<RespiratoryRateSample> getAllSamples(final long timestampFrom, final long timestampTo) {
@ -39,21 +38,6 @@ public class TestRespiratoryRateSampleProvider implements TimeSampleProvider<Res
return samples;
}
@Override
public void addSample(final RespiratoryRateSample timeSample) {
throw new UnsupportedOperationException("read-only sample provider");
}
@Override
public void addSamples(final List<RespiratoryRateSample> timeSamples) {
throw new UnsupportedOperationException("read-only sample provider");
}
@Override
public RespiratoryRateSample createSample() {
throw new UnsupportedOperationException("read-only sample provider");
}
@Nullable
@Override
public RespiratoryRateSample getLatestSample() {

View File

@ -22,11 +22,10 @@ import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.test.TestDeviceRand;
import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample;
public class TestSpo2SampleProvider implements TimeSampleProvider<Spo2Sample> {
public class TestSpo2SampleProvider extends AbstractTestSampleProvider<Spo2Sample> {
@NonNull
@Override
public List<Spo2Sample> getAllSamples(final long timestampFrom, final long timestampTo) {
@ -44,21 +43,6 @@ public class TestSpo2SampleProvider implements TimeSampleProvider<Spo2Sample> {
return samples;
}
@Override
public void addSample(final Spo2Sample timeSample) {
throw new UnsupportedOperationException("read-only sample provider");
}
@Override
public void addSamples(final List<Spo2Sample> timeSamples) {
throw new UnsupportedOperationException("read-only sample provider");
}
@Override
public Spo2Sample createSample() {
throw new UnsupportedOperationException("read-only sample provider");
}
@Nullable
@Override
public Spo2Sample getLatestSample() {

View File

@ -22,11 +22,10 @@ import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.test.TestDeviceRand;
import nodomain.freeyourgadget.gadgetbridge.model.StressSample;
public class TestStressSampleProvider implements TimeSampleProvider<StressSample> {
public class TestStressSampleProvider extends AbstractTestSampleProvider<StressSample> {
@NonNull
@Override
public List<StressSample> getAllSamples(final long timestampFrom, final long timestampTo) {
@ -44,21 +43,6 @@ public class TestStressSampleProvider implements TimeSampleProvider<StressSample
return samples;
}
@Override
public void addSample(final StressSample timeSample) {
throw new UnsupportedOperationException("read-only sample provider");
}
@Override
public void addSamples(final List<StressSample> timeSamples) {
throw new UnsupportedOperationException("read-only sample provider");
}
@Override
public StressSample createSample() {
throw new UnsupportedOperationException("read-only sample provider");
}
@Nullable
@Override
public StressSample getLatestSample() {

View File

@ -22,11 +22,10 @@ import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.test.TestDeviceRand;
import nodomain.freeyourgadget.gadgetbridge.model.TemperatureSample;
public class TestTemperatureSampleProvider implements TimeSampleProvider<TemperatureSample> {
public class TestTemperatureSampleProvider extends AbstractTestSampleProvider<TemperatureSample> {
@NonNull
@Override
public List<TemperatureSample> getAllSamples(final long timestampFrom, final long timestampTo) {
@ -45,21 +44,6 @@ public class TestTemperatureSampleProvider implements TimeSampleProvider<Tempera
return samples;
}
@Override
public void addSample(final TemperatureSample timeSample) {
throw new UnsupportedOperationException("read-only sample provider");
}
@Override
public void addSamples(final List<TemperatureSample> timeSamples) {
throw new UnsupportedOperationException("read-only sample provider");
}
@Override
public TemperatureSample createSample() {
throw new UnsupportedOperationException("read-only sample provider");
}
@Nullable
@Override
public TemperatureSample getLatestSample() {

View File

@ -71,6 +71,16 @@ public class XiaomiHeartRateRestingSampleProvider implements TimeSampleProvider<
return null;
}
@Nullable
@Override
public HeartRateSample getLatestSample(final long until) {
final XiaomiDailySummarySample sample = dailySummarySampleProvider.getLatestSample(until);
if (sample != null) {
return new XiaomiHeartRateRestingSample(sample);
}
return null;
}
@Nullable
@Override
public HeartRateSample getFirstSample() {

View File

@ -84,6 +84,26 @@ public class XiaomiManualSampleProvider extends AbstractTimeSampleProvider<Xiaom
return samples.get(0);
}
@Nullable
public XiaomiManualSample getLatestSample(final int type, final long until) {
final QueryBuilder<XiaomiManualSample> qb = getSampleDao().queryBuilder();
final Device dbDevice = DBHelper.findDevice(getDevice(), getSession());
if (dbDevice == null) {
// no device, no sample
return null;
}
final Property deviceProperty = getDeviceIdentifierSampleProperty();
qb.where(deviceProperty.eq(dbDevice.getId()))
.where(XiaomiManualSampleDao.Properties.Timestamp.le(until))
.where(XiaomiManualSampleDao.Properties.Type.eq(type))
.orderDesc(getTimestampSampleProperty()).limit(1);
final List<XiaomiManualSample> samples = qb.build().list();
if (samples.isEmpty()) {
return null;
}
return samples.get(0);
}
@Nullable
public XiaomiManualSample getFirstSample(final int type) {
final QueryBuilder<XiaomiManualSample> qb = getSampleDao().queryBuilder();

View File

@ -71,6 +71,16 @@ public class XiaomiPaiSampleProvider implements TimeSampleProvider<PaiSample> {
return null;
}
@Nullable
@Override
public PaiSample getLatestSample(final long until) {
final XiaomiDailySummarySample sample = dailySummarySampleProvider.getLatestSample(until);
if (sample != null) {
return new XiaomiPaiSample(sample);
}
return null;
}
@Nullable
@Override
public PaiSample getFirstSample() {

View File

@ -76,6 +76,16 @@ public class XiaomiTemperatureSampleProvider implements TimeSampleProvider<Tempe
return null;
}
@Nullable
@Override
public TemperatureSample getLatestSample(final long until) {
final XiaomiManualSample sample = manualSampleProvider.getLatestSample(XiaomiManualSampleProvider.TYPE_TEMPERATURE, until);
if (sample != null) {
return new XiaomiTemperatureSample(sample);
}
return null;
}
@Nullable
@Override
public TemperatureSample getFirstSample() {