Skip to content

Commit

Permalink
Add support for reading voltage and movement counter
Browse files Browse the repository at this point in the history
Battery voltage and movement counter is read when fetching data
from Ruuvi. Movement counter is built in Ruuvi, and resets to zero
when exceeding 254. See Ruuvi documentation for more information:
https://ruuvi.com/acceleration-or-movement-measurement/

Resolves #8
  • Loading branch information
miikasda committed Jul 16, 2024
1 parent 7e770dd commit 452b4c3
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 8 deletions.
6 changes: 5 additions & 1 deletion qml/pages/GetDataPage.qml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
Skruuvi - Reader for Ruuvi sensors
Copyright (C) 2023 Miika Malin
Copyright (C) 2023-2024 Miika Malin
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -262,6 +262,10 @@ Page {
loadingScreen.text = "Connected, fetching data"
} else if (data[0] === "data_received_amount") {
loadingScreen.text = "Connected, received " + data[1] + " readings"
} else if (data[0] === "extra_data") {
// Update voltage and movement counter
db.setVoltage(selectedDevice.deviceAddress, data[1])
db.setMovement(selectedDevice.deviceAddress, data[2])
} else if (data[0] === "failed") {
loadingScreen.running = false;
failureOverlay.visible = true;
Expand Down
83 changes: 82 additions & 1 deletion qml/pages/SelectDevicePage.qml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
Skruuvi - Reader for Ruuvi sensors
Copyright (C) 2023 Miika Malin
Copyright (C) 2023-2024 Miika Malin
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -112,6 +112,8 @@ Page {
deviceModel.append({
deviceName: device.deviceName,
deviceAddress: device.deviceAddress,
deviceVoltage: device.deviceVoltage,
deviceMovement: device.deviceMovement,
showBluetoothIcon: false
});
}
Expand Down Expand Up @@ -164,6 +166,7 @@ Page {
}

Image {
id: btIcon
source: "image://theme/icon-s-bluetooth"
width: Theme.iconSizeSmall
height: Theme.iconSizeSmall
Expand All @@ -175,6 +178,32 @@ Page {
}
}

Image {
id: batteryIcon
source: "image://theme/icon-m-battery"
width: Theme.iconSizeSmall
height: Theme.iconSizeSmall
anchors {
left: topLabel.right
leftMargin: Theme.paddingMedium
verticalCenter: parent.verticalCenter
verticalCenterOffset: -topLabel.height / 2
}
}

Image {
id: movementIcon
source: "image://theme/icon-s-sync"
width: Theme.iconSizeSmall
height: Theme.iconSizeSmall
anchors {
left: voltageLabel.right
leftMargin: Theme.paddingMedium
verticalCenter: parent.verticalCenter
verticalCenterOffset: -topLabel.height / 2
}
}

Label {
id: topLabel
text: model.deviceName
Expand All @@ -185,6 +214,25 @@ Page {
}

Label {
id: voltageLabel
text: model.deviceVoltage + " V"
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: -topLabel.height / 2
anchors.left: batteryIcon.right
anchors.leftMargin: Theme.paddingSmall
}

Label {
id: movementLabel
text: model.deviceMovement + " Moves"
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: -topLabel.height / 2
anchors.left: movementIcon.right
anchors.leftMargin: Theme.paddingSmall
}

Label {
id: bottomLabel
anchors.top: topLabel.bottom
text: model.deviceAddress
font.pixelSize: Theme.fontSizeSmall
Expand Down Expand Up @@ -301,6 +349,37 @@ Page {
}
}

Connections {
target: db
onVoltageUpdated: {
// Find the device with the matching mac address in the model
var deviceFound = false;
for (var i = 0; i < deviceModel.count; i++) {
var device = deviceModel.get(i);
if (device.deviceAddress === mac) {
deviceFound = true;
// Update the voltage for the matched device
deviceModel.setProperty(i, "deviceVoltage", voltage.toString());
console.log("Voltage updated for " + mac);
break;
}
}
}
onMovementUpdated: {
var deviceFound = false;
for (var i = 0; i < deviceModel.count; i++) {
var device = deviceModel.get(i);
if (device.deviceAddress === mac) {
deviceFound = true;
// Update the movement for the matched device
deviceModel.setProperty(i, "deviceMovement", movement.toString());
console.log("Movement updated for " + mac);
break;
}
}
}
}

Connections {
target: ld
onDeviceFound: {
Expand All @@ -320,6 +399,8 @@ Page {
deviceModel.append({
deviceName: deviceName,
deviceAddress: deviceAddress,
deviceVoltage: "NA",
deviceMovement: "NA",
showBluetoothIcon: true
});
}
Expand Down
19 changes: 16 additions & 3 deletions qml/pages/ruuvi_read.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
License:
Skruuvi - Reader for Ruuvi sensors
Copyright (C) 2023 Miika Malin
Copyright (C) 2023-2024 Miika Malin
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -43,8 +43,9 @@
# Charasteristic UUIDS
UART_RX_CHAR_UUID = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
UART_TX_CHAR_UUID = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
# Magic value for log read
LOG_READ = 0x11
# Magic values
LOG_READ = 0x11 # Log read command
ADV_DATA = 0x05 # Header information for advertisement data


class RuuviTagReader:
Expand Down Expand Up @@ -97,6 +98,18 @@ def handle_rx(self, _, data):
"data_received_amount",
self.data_received_amount
])
elif data[0] == ADV_DATA:
if len(data) != 18:
print("Wrong advertisement data size", flush=True)
else:
print("Advertisement data received", flush=True)
dat = struct.unpack('>BhHHhhhHBH', data)
voltage = ((dat[7] >> 5) + 1600) / 1000
movement_counter = dat[8]
pyotherside.send([
"extra_data",
round(voltage, 2), movement_counter
])

async def read_log_data(self):
print(f"Searching for Ruuvi {self.device_address}", flush=True)
Expand Down
55 changes: 53 additions & 2 deletions src/database.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
Skruuvi - Reader for Ruuvi sensors
Copyright (C) 2023 Miika Malin
Copyright (C) 2023-2024 Miika Malin
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -77,6 +77,10 @@ database::database(QObject* parent) : QObject(parent) {
"FOREIGN KEY (device) REFERENCES devices(mac))";
executeQuery(createAirPressureTableQuery);

// Colums added after initial release needs to be appended
checkAndAddColumn("devices", "voltage", "REAL");
checkAndAddColumn("devices", "movement", "INT");

}

void database::executeQuery(const QString& queryStr) {
Expand All @@ -86,6 +90,49 @@ void database::executeQuery(const QString& queryStr) {
}
}

void database::checkAndAddColumn(const QString &tableName, const QString &columnName, const QString &columnType) {
QSqlQuery query(db);
query.exec("PRAGMA table_info(" + tableName + ")");
bool columnExists = false;
while (query.next()) {
if (query.value(1).toString() == columnName) {
columnExists = true;
break;
}
}
if (!columnExists) {
qDebug() << "Adding column " << columnName << " to table " << tableName;
QString alterTableQuery = "ALTER TABLE " + tableName + " ADD COLUMN " + columnName + " " + columnType;
executeQuery(alterTableQuery);
}
}

void database::setVoltage(const QString &mac, double voltage) {
QSqlQuery query(db);
query.prepare("UPDATE devices SET voltage = :voltage WHERE mac = :mac");
query.bindValue(":voltage", voltage);
query.bindValue(":mac", mac);

if (!query.exec()) {
qDebug() << "Error setting voltage:" << query.lastError().text();
} else {
emit voltageUpdated(mac, voltage); // Emit the new voltage reading
}
}

void database::setMovement(const QString &mac, int movement) {
QSqlQuery query(db);
query.prepare("UPDATE devices SET movement = :movement WHERE mac = :mac");
query.bindValue(":movement", movement);
query.bindValue(":mac", mac);

if (!query.exec()) {
qDebug() << "Error setting movement:" << query.lastError().text();
} else {
emit movementUpdated(mac, movement); // Emit the new movement reading
}
}

void database::inputRawData(QString deviceAddress, QString deviceName, const QVariantList& data) {
// Create a QThread to run the function in a separate thread
QThread* thread = new QThread(this);
Expand Down Expand Up @@ -141,16 +188,20 @@ QVariantList database::getDevices()
{
QVariantList devices;

QString selectQuery = "SELECT mac, name FROM devices";
QString selectQuery = "SELECT mac, name, voltage, movement FROM devices";
QSqlQuery query(db);
if (query.exec(selectQuery)) {
while (query.next()) {
QString mac = query.value(0).toString();
QString name = query.value(1).toString();
QString voltage = query.value("voltage").isNull() ? "NA" : QString::number(query.value("voltage").toDouble());
QString movement = query.value("movement").isNull() ? "NA" : QString::number(query.value("movement").toInt());

QVariantMap device;
device["deviceName"] = name;
device["deviceAddress"] = mac;
device["deviceVoltage"] = voltage;
device["deviceMovement"] = movement;

devices.append(device);
}
Expand Down
7 changes: 6 additions & 1 deletion src/database.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
Skruuvi - Reader for Ruuvi sensors
Copyright (C) 2023 Miika Malin
Copyright (C) 2023-2024 Miika Malin
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -37,12 +37,17 @@ class database : public QObject {
Q_INVOKABLE void renameDevice(const QString deviceAddress, const QString newDeviceName);
Q_INVOKABLE void removeDevice(const QString deviceAddress);
Q_INVOKABLE QString exportCSV(const QString deviceAddress, const QString deviceName, int startTime, int endTime);
Q_INVOKABLE void setVoltage(const QString &mac, double voltage);
Q_INVOKABLE void setMovement(const QString &mac, int movement);

private:
QSqlDatabase db;
void checkAndAddColumn(const QString &tableName, const QString &columnName, const QString &columnType);

signals:
void inputFinished();
void voltageUpdated(const QString &mac, double voltage);
void movementUpdated(const QString &mac, int movement);
};

#endif // DATABASE_H

0 comments on commit 452b4c3

Please sign in to comment.