summaryrefslogtreecommitdiff
path: root/daemon/sensorPlugins/stepCounter.cpp
blob: fd09e81ce5531049e70ddf388c50b79e1cb0b5ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/*
 * Copyright (C) 2023 Arseniy Movshev <dodoradio@outlook.com>
 * This file is part of sensorlogd, a sensor logger for the AsteroidOS smartwatch OS.
 *
 * sensorlogd is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 * sensorlogd 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
 */

#include <QDate>
#include <QDateTime>
#include <QDebug>
#include <QString>
#include <QTime>
#include <QTimer>
#include <QtSensors/QStepCounterSensor>
#include <QSettings>
#include <time.h>

#include "../logger.h"

#include "stepCounter.h"

StepCounterPlugin::StepCounterPlugin(QObject* parent, int initInterval, bool daemonFresh)
    : QObject(parent)
{
    interval = initInterval;

    stepcounterSensor = new QStepCounterSensor(this);
    stepcounterSensor->start();

    qDebug() << "step counter sensor is enabled. interval is (ms) " << interval;
    recordIntervalTimer = new QTimer(this);
    connect(recordIntervalTimer, SIGNAL(timeout()), this, SLOT(triggerRecording()));
    recordIntervalTimer->setSingleShot(true);
    recordIntervalTimer->start(interval);
    QDateTime currDateTime = QDateTime::currentDateTime();

    setupFilePath(sensorPathPrefix);
    while (!stepcounterSensor->isActive()) { }
    m_settings = new QSettings("asteroid", "sensorlogd");

    if (dayFileExists(sensorPathPrefix) && daemonFresh) {
        QStringList lastLineData = fileGetPrevRecord(sensorPathPrefix);
        lastRecordTime = QDateTime::currentDateTime();
        m_stepsOffset = stepcounterSensor->reading()->steps() - lastLineData[1].toInt(); // we reset the step count, ignoring all steps that may have been taken while the daemon isn't running. Devices which count steps independently will need custom code.
    } else if (dayFileExists) {
        lastRecordTime = QDateTime::currentDateTime();
        m_stepsOffset = m_settings->value("StepCounterPrivate/stepsOffset", 0).toInt();
    }
    m_settings->setValue("StepCounterPrivate/stepsOffset", m_stepsOffset);
}

void StepCounterPlugin::timeUpdate()
{
    QDateTime currDateTime = QDateTime::currentDateTime();
    uint elapsed = currDateTime.toMSecsSinceEpoch() - lastRecordTime.toMSecsSinceEpoch();
    qDebug() << "time until next steps recording" << recordIntervalTimer->remainingTime() << " elapsed = " << elapsed << " lastRecordTime " << lastRecordTime.toMSecsSinceEpoch();
    if (elapsed > interval) { // if too much time has passed, reset the timer and record
        triggerRecording();
    } else { // otherwise, restart the timer and compensate for time spent in suspend
        recordIntervalTimer->start(interval - elapsed);
    }
}

void StepCounterPlugin::triggerRecording()
{
    qDebug() << "stepcounter interval recording";
    int rawSteps = stepcounterSensor->reading()->steps();
    if (lastRecordTime.date() != QDate::currentDate()) { // ok, so the date has changed.
        if (dayFileExists(sensorPathPrefix)) { // this likely means we have just had a system time change
            QStringList lastLineData = fileGetPrevRecord(sensorPathPrefix);
            m_stepsOffset = rawSteps - lastLineData[1].toInt(); // we scrap the current steps value, recover the last reading from today's file and count from there
                // The reset is necessary because asteroid doesn't have robust time when it boots up, it takes a while for that to happen. So, instead of dealing with that, we just reset the counter every time there's a date change
        } else if (lastRecordTime.date() == QDate::currentDate().addDays(-1)) { // this means that a midnight just passed
            int steps = rawSteps - m_stepsOffset;
            fileAddRecord(sensorPathPrefix, QString::number(steps), QDateTime(QDate::currentDate().addDays(-1), QTime(23, 59, 59))); // this writes the current step count to the last second of the previous day
            m_stepsOffset = rawSteps; // and then we 'reset' the step counter
        }
        m_settings->setValue("StepCounterPrivate/stepsOffset", m_stepsOffset);
        qDebug() << "date change detected. Step counter value is " << rawSteps << " and offset is " << m_stepsOffset;
    } else {
        int steps = rawSteps - m_stepsOffset;
        qDebug() << QDateTime::currentDateTime().toString("hh:mm:ss") << " : " << steps << stepcounterSensor->isActive();
        // we probably ought to do some error checking here
        if (steps < fileGetPrevRecord(sensorPathPrefix)[1].toInt()) {
            qDebug() << "error: offset value is less than previous value - not recording"; // this is an error condition which is either caused by a bad offset value or by the sensor being slow and returning a bad value
            return;
        }
        fileAddRecord(sensorPathPrefix, QString::number(steps));
    }
    lastRecordTime = QDateTime::currentDateTime();
}