Lights, Doc, Db
- Now lights works with DialogFlow - Database automatically update data from user's fitbit - Doc is written well (well.. it is ok) - Added logging here and there - Removed unused code - Improved code reading and code quality
This commit is contained in:
@@ -5,30 +5,48 @@ import device.fitbitdata.Sleep;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.sql.*;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
// todo add docs
|
||||
/**
|
||||
* Handle the connection to the SQLite database that stores our tasks.
|
||||
* @author <a href="mailto:luigi.derussis@uniupo.it">Luigi De Russis</a>
|
||||
* @version 1.1 (06/05/2018)
|
||||
* Classe che si connette al database e permette di aggiornare i dati in modo automatico tramite dei runnable
|
||||
*/
|
||||
public class Database {
|
||||
|
||||
public static final String DB_LOCATION = "jdbc:sqlite:src/main/resources/";
|
||||
public static final String DB_NAME = "user_data.db";
|
||||
|
||||
private static final Calendar CALENDAR = Calendar.getInstance();
|
||||
/**
|
||||
* Un logger per scrivere a console eventuali errori o informazioni
|
||||
*/
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Database.class);
|
||||
|
||||
/**
|
||||
* Il percorso di dove trovare il database, strutturato in: <interfaccia>:<implementazione>:<percorso vero e proprio>
|
||||
*/
|
||||
public static final String DB_LOCATION = "jdbc:sqlite:";
|
||||
|
||||
/**
|
||||
* Il nome del database (aka il nome del file)
|
||||
*/
|
||||
public static final String DB_NAME = "user_data.db";
|
||||
|
||||
/**
|
||||
* Un calendario, visto che ci serve sapere quando inseriamo i dati
|
||||
*/
|
||||
private static final Calendar CALENDAR = Calendar.getInstance();
|
||||
|
||||
/**
|
||||
* Una costante che indica quanti millisecondi ci sono in un minuto (utile per le conversioni)
|
||||
*/
|
||||
private static final int MINUTES_TO_MILLISEC = 60000;
|
||||
|
||||
/**
|
||||
* L'unica istanza del database (dato che e' una classe Singleton)
|
||||
*/
|
||||
private static Database instance;
|
||||
|
||||
/**
|
||||
* La connessione al database
|
||||
*/
|
||||
private final Connection conn;
|
||||
|
||||
/**
|
||||
@@ -46,7 +64,7 @@ public class Database {
|
||||
conn = DriverManager.getConnection(DB_LOCATION + DB_NAME);
|
||||
Statement statement = conn.createStatement();
|
||||
statement.execute("CREATE TABLE IF NOT EXISTS total (day DATE PRIMARY KEY, sleep_time INTEGER, heart_rate DOUBLE, steps INTEGER)");
|
||||
statement.execute("CREATE TABLE IF NOT EXISTS heart (day_hour DATE PRIMARY KEY, heart_rate DOUBLE)");
|
||||
statement.execute("CREATE TABLE IF NOT EXISTS heart (day_hour DATE PRIMARY KEY, rate DOUBLE)");
|
||||
statement.execute("CREATE TABLE IF NOT EXISTS sleep (sleep_start DATE PRIMARY KEY, sleep_end DATE, duration INTEGER)");
|
||||
}
|
||||
|
||||
@@ -58,8 +76,10 @@ public class Database {
|
||||
* <li>'heart' battito + orario</li>
|
||||
* <li>'sleep' inizio + fine + durata</li>
|
||||
* </ul>
|
||||
* <br>
|
||||
* L'implementazione e' synchronized (si spera thread safe)
|
||||
*/
|
||||
public static Database getInstance() {
|
||||
public synchronized static Database getInstance() {
|
||||
try {
|
||||
instance = instance==null? new Database():instance;
|
||||
} catch (SQLException e) {
|
||||
@@ -69,82 +89,96 @@ public class Database {
|
||||
}
|
||||
|
||||
/**
|
||||
* Prendi il Runnable che automaticamente gestisce l'inserimento dei dati orari (per ora solo il battito cardiaco)
|
||||
* Prendi il Runnable che automaticamente gestisce l'inserimento dei dati orari (per ora solo il battito cardiaco)<br>
|
||||
* <br>
|
||||
* Il runnable e' synchronized (si spera thread safe)
|
||||
* @param fitbit la classe che contiene i dati aggiornati
|
||||
* @return un Runnable
|
||||
*/
|
||||
public Runnable insertHourlyData(Fitbit fitbit) {
|
||||
Runnable runnable = () -> {
|
||||
boolean notInterrupted = true;
|
||||
boolean retry = false;
|
||||
double heartRate = 0;
|
||||
Date now = null;
|
||||
return new Runnable() {
|
||||
@Override
|
||||
public synchronized void run() {
|
||||
boolean notInterrupted = true;
|
||||
boolean retry = false;
|
||||
double heartRate = 0;
|
||||
Timestamp now = null;
|
||||
|
||||
while(notInterrupted) {
|
||||
try {
|
||||
wait((retry? 1:59-CALENDAR.get(Calendar.MINUTE)) * 60000);
|
||||
if (retry == false) {
|
||||
heartRate = fitbit.getHeartRate(60);
|
||||
now = CALENDAR.getTime();
|
||||
while (notInterrupted) {
|
||||
CALENDAR.setTimeInMillis(System.currentTimeMillis());
|
||||
try {
|
||||
wait((retry ? 1:58-CALENDAR.get(Calendar.MINUTE)) * MINUTES_TO_MILLISEC);
|
||||
CALENDAR.setTimeInMillis(System.currentTimeMillis());
|
||||
if (retry == false) {
|
||||
now = new Timestamp(CALENDAR.getTimeInMillis());
|
||||
heartRate = fitbit.getHeartRate(60);
|
||||
}
|
||||
|
||||
conn.createStatement().execute("INSERT INTO heart (day_hour, rate) VALUES ( ' " + now + " ', '" + heartRate + "')");
|
||||
LOG.info(CALENDAR.getTime() + " > Ho inserito i dati orari "+now);
|
||||
retry = false;
|
||||
wait(MINUTES_TO_MILLISEC);
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
notInterrupted = false;
|
||||
} catch (Exception e) {
|
||||
LOG.error(CALENDAR.getTime() + " " + e.getLocalizedMessage() + " > Non e' stato possibile aggingere i dati orari al database, riprovo fra un minuto "+now);
|
||||
retry = true;
|
||||
}
|
||||
|
||||
conn.createStatement().execute("INSERT INTO heart (day_hour, rate) VALUE ( ' " + now + " ', '" + heartRate + "')");
|
||||
retry = false;
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
notInterrupted = false;
|
||||
} catch (Exception e) {
|
||||
LOG.error("Non e' stato possibile aggingere i dati orari al database, riprovo fra un minuto");
|
||||
retry = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
return runnable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prendi il Runnable che automaticamente gestisce l'inserimento dei dati giornalieri
|
||||
* Prendi il Runnable che automaticamente gestisce l'inserimento dei dati giornalieri<br>
|
||||
* <br>
|
||||
* Il runnable e' synchronized (si spera thread safe)
|
||||
* @param fitbit la classe che contiene i dati aggiornati
|
||||
* @return un Runnable
|
||||
*/
|
||||
public Runnable insertDailyData(Fitbit fitbit) {
|
||||
Runnable runnable = () -> {
|
||||
boolean notInterrupted = true;
|
||||
boolean retry = false;
|
||||
double heartRate = 0;
|
||||
long sleepTime = 0;
|
||||
long steps = 0;
|
||||
List<Sleep.SleepData> sleepDatas = null;
|
||||
Date now = null;
|
||||
return new Runnable() {
|
||||
@Override
|
||||
public synchronized void run() {
|
||||
boolean notInterrupted = true;
|
||||
boolean retry = false;
|
||||
double heartRate = 0;
|
||||
long sleepTime = 0;
|
||||
long steps = 0;
|
||||
List<Sleep.SleepData> sleepDatas = null;
|
||||
Timestamp now = null;
|
||||
|
||||
while (notInterrupted) {
|
||||
int hourToWait = 23 - CALENDAR.get(Calendar.HOUR);
|
||||
while (notInterrupted) {
|
||||
CALENDAR.setTimeInMillis(System.currentTimeMillis());
|
||||
try {
|
||||
wait((retry? 1:(22-CALENDAR.get(Calendar.HOUR))*60) * MINUTES_TO_MILLISEC);
|
||||
CALENDAR.setTimeInMillis(System.currentTimeMillis());
|
||||
if (retry == false) {
|
||||
heartRate = fitbit.getHeartRate(60 * 24);
|
||||
sleepTime = fitbit.getHoursSleep();
|
||||
sleepDatas = fitbit.getDetailedSleep();
|
||||
steps = fitbit.getSteps();
|
||||
now = new Timestamp(CALENDAR.getTimeInMillis());
|
||||
}
|
||||
|
||||
try {
|
||||
wait(hourToWait * 3600000);
|
||||
if (retry == false) {
|
||||
heartRate = fitbit.getHeartRate(60 * 24);
|
||||
sleepTime = fitbit.getHoursSleep();
|
||||
sleepDatas = fitbit.getDetailedSleep();
|
||||
steps = fitbit.getSteps();
|
||||
now = CALENDAR.getTime();
|
||||
conn.createStatement().execute("INSERT INTO total (day, sleep_time, heart_rate, steps) VALUES ( '" + now + "', '" + sleepTime + "', '" + heartRate + "', '" + steps + "' )");
|
||||
for (Sleep.SleepData data : sleepDatas)
|
||||
conn.createStatement().execute("INSERT INTO total (sleep_start, sleep_end, duration) VALUES ( '" + data.start_date + "', '" + data.end_date + "', '" + data.duration + "' )");
|
||||
LOG.info(CALENDAR.getTime() + " > Ho inserito i dati giornalieri");
|
||||
retry = false;
|
||||
wait(MINUTES_TO_MILLISEC);
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
notInterrupted = false;
|
||||
} catch (Exception e) {
|
||||
LOG.error(CALENDAR.getTime() + " " + e.getLocalizedMessage() + " > Non e' stato possibile aggingere i dati della giornata al database, riprovo fra un minuto");
|
||||
retry = true;
|
||||
}
|
||||
|
||||
conn.createStatement().execute("INSERT INTO total (day, sleep_time, heart_rate, steps) VALUE ( '" + now + "', '" + sleepTime + "', '" + heartRate + "', '" + steps + "' )");
|
||||
for (Sleep.SleepData data : sleepDatas)
|
||||
conn.createStatement().execute("INSERT INTO total (sleep_start, sleep_end, duration) VALUE ( '" + data.start_date + "', '" + data.end_date + "', '" + data.duration + "' )");
|
||||
retry = false;
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
notInterrupted = false;
|
||||
} catch (Exception e) {
|
||||
LOG.error("Non e' stato possibile aggingere i dati orari al database, riprovo fra un minuto");
|
||||
retry = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
return runnable;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user