Fix and last TODO

- Various fix in code
- Fitbit now support steps by minutes
- Added data retrieving from WebHook
- Added checkSteps
This commit is contained in:
2018-09-19 22:57:11 +02:00
parent 2ed9eef8d1
commit eea9dd50e0
14 changed files with 284 additions and 106 deletions

View File

@@ -102,11 +102,17 @@ public class DialogFlowWebHook {
} catch (NullPointerException e) {
LOG.error("NESSUNA AZIONE TROVATA: "+ inputAction);
text = ERROR;
} catch (Exception e) {
LOG.error("Qualcosa e' andato storto: " + e.getMessage());
text = ERROR;
}
if(text == null)
text = input.getResult().getFulfillment().getSpeech();
for(String param: inputParam.keySet())
text = text.replace("@"+param, inputParam.get(param).getAsString());
LOG.info("RISPOSTA: " + text);
output.setDisplayText(text);
output.setSpeech(text);
@@ -135,7 +141,8 @@ public class DialogFlowWebHook {
*
* @param params una mappa contenente tutti i parametri impostati da dialogflow
* @return Una stringa che verra' usata come messaggio o null se non si vuole
* @throws Exception una qualunque eccezione che si vuole lanciare
*/
String doAction(Map<String, JsonElement> params);
String doAction(Map<String, JsonElement> params) throws Exception;
}
}

View File

@@ -1,11 +1,5 @@
package device;
import java.io.IOException;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import device.fitbitdata.HeartRate;
import device.fitbitdata.Sleep;
import device.fitbitdata.Steps;
@@ -13,6 +7,12 @@ import oauth.AuthFitbit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Classe che permette di ricevere i dati di un particolare account FitBit
*/
@@ -83,19 +83,39 @@ public class Fitbit {
* Ricevi i passi che l'utente ha effettuato nell'ultimo giorno
*
* @return un intero rappresentante i passi effettuati
* @throws IOException nel caso la richiesta non vada a buon fine
*/
public synchronized int getSteps() {
steps = update(Steps.class, steps, "1" + USER + "activities/steps/date/today/1w.json");
steps = update(Steps.class, steps, "1" + USER + "activities/steps/date/today/1d/1min.json");
return steps.getSteps();
}
/**
* Ricevi i passi che l'utente ha effettuato negli ultimi minuti richiesti
*
* @param lastMinutes gli ultimi minuti che si vogliono vedere (positivi e !=0 se no ritorno -1)
* @return un intero rappresentante i passi effettuati
*/
public synchronized int getSteps(int lastMinutes) {
if(lastMinutes<=0)
return -1;
steps = update(Steps.class, steps, "1" + USER + "activities/steps/date/today/1d/1min.json");
List<Map<String, Object>> list = steps.getStepsData();
final int now = list.size()-1;
int totalSteps = 0;
for(int i=0; i<lastMinutes; i++)
totalSteps += (int)list.get(now-i).get("value");
return totalSteps;
}
/**
* Ricevi il battito cardiaco dell'utente<br>
* Il risultato e' una media del battito che l'utente ha avuto negli ultimi 15 minuti
*
* @return un intero rappresentante la media del battito cardiaco degli ultimi 15 minuti
* @throws IOException nel caso la richiesta non vada a buon fine
*/
public synchronized double getHeartRate() { return getHeartRate(15); }
@@ -105,7 +125,6 @@ public class Fitbit {
*
* @param lastMinutes fino a quanti minuti bisogna tenere conto (positivi e !=0 se no ritorno -1)
* @return un intero rappresentante la media del battito cardiaco degli ultimi minuti specificati
* @throws IOException nel caso la richiesta non vada a buon fine
*/
public synchronized double getHeartRate(int lastMinutes) {
if(lastMinutes<=0)
@@ -127,7 +146,6 @@ public class Fitbit {
* Ricevi le ore di sonno che l'utente ha fatto nell'ultimo giorno
*
* @return un intero rappresentante le ore passate a dormire
* @throws IOException nel caso la richiesta non vada a buon fine
*/
public synchronized long getHoursSleep() {
sleep = update(Sleep.class, sleep,"1.2" + USER + "sleep/date/today.json");
@@ -141,7 +159,6 @@ public class Fitbit {
* - la durata del sonno<br>
* - la data di fine<br>
* @return una lista contenente ogni volta che l'utente ha dormito
* @throws IOException
*/
public synchronized List<Sleep.SleepData> getDetailedSleep() {
sleep = update(Sleep.class, sleep,"1.2" + USER + "sleep/date/today.json");
@@ -169,16 +186,17 @@ public class Fitbit {
return variable;
} catch (NullPointerException e) {
// do nothing and update
} finally {
LOG.info("Updating " + varClass.getSimpleName() + " form " + BASIC_URL + url);
try {
variable = auth.run(BASIC_URL + url, varClass);
latestRequest.put(varClass, System.currentTimeMillis());
} catch (IOException e) {
LOG.error("Non sono riuscito a prender i dati aggiornati: " + e.getMessage());
}
return variable;
}
LOG.info("Updating " + varClass.getSimpleName() + " form " + BASIC_URL + url);
try {
variable = auth.run(BASIC_URL + url, varClass);
latestRequest.put(varClass, System.currentTimeMillis());
} catch (IOException e) {
LOG.error("Non sono riuscito a prender i dati aggiornati: " + e.getMessage());
e.printStackTrace();
}
return variable;
}
/**

View File

@@ -80,6 +80,7 @@ public class Hue {
if(allLights.isEmpty())
throw new NullPointerException("Non e' stato possibile connettersi alle luci");
// TODO GIOVEDI impostare una luminosita' e un colore di default
double bri = 0;
double hue = 0;
for (String name: allLights.keySet()) {
@@ -147,7 +148,7 @@ public class Hue {
else if (num>100)
num=100;
setState("bri", (int) (num*MAX_BRIGHTNESS)/100 );
setState("bri", (int) (num*MAX_BRIGHTNESS)/100, true);
brightness.set(num);
}
@@ -196,23 +197,13 @@ public class Hue {
public void changeColor(String colorName) {
for (String regex: COLORS.keySet())
if(colorName.matches("(?i)" + regex))
setState("xy", COLORS.get(regex));
setState("xy", COLORS.get(regex), true);
}
/**
* Modifica il colore delle luci in modo da fare un bel effetto arcobaleno continuo
*/
public void colorLoop() { setState("effect", "colorloop"); }
/**
* Invia una richiesta a tutte le luci hue con l'attributo selezionato ed il suo valore<br>
* Con esso invia anche una transition:20 in modo che sia piu fluido il cambiamento
* @param attribute l'attributo che si vuole cambiare
* @param value il valore da inserire
*/
public void setState(String attribute, Object value){
setState(attribute, value, true);
}
public void colorLoop() { setState("effect", "colorloop", false); }
/**
* Invia una richiesta a tutte le luci hue con l'attributo selezionato ed il suo valore<br>
@@ -221,7 +212,7 @@ public class Hue {
* @param value il valore da inserire
* @param transition se includere la transizione o meno
*/
public void setState(String attribute, Object value, boolean transition){
private void setState(String attribute, Object value, boolean transition){
Map<String, Object> map = new HashMap<>();
map.put(attribute, value);
if(transition)
@@ -233,7 +224,7 @@ public class Hue {
* Invia una richiesta a tutte le luci hue con gli attributi selezionati ed il loro valore
* @param attributes una mappa di attributi -> valori
*/
public synchronized void setState(Map<String, Object> attributes) {
private synchronized void setState(Map<String, Object> attributes) {
String body = GsonFactory.getDefaultFactory().getGson().toJson(attributes);
LOG.info("Setting: " + body);
for (String light : allLights.keySet()) {

View File

@@ -1,19 +1,22 @@
package device.fitbitdata;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Steps extends FitbitData {
private int steps = 0;
private int steps;
private List<Map<String, Object>> stepsData;
@JsonProperty("activities-steps")
public void setSteps(Map<String, String>[] array) {
private void setSteps(Map<String, String>[] array) {
SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd");
Date now = new Date();
String strDate = sdfDate.format(now);
@@ -23,6 +26,12 @@ public class Steps extends FitbitData {
steps = Integer.parseInt(map.get("value"));
}
@JsonProperty("activities-steps-intraday")
private void setDetailedSteps(Map<String, Object> map) {
stepsData = new ArrayList<>((List<Map<String, Object>>) map.get("dataset"));
}
public void setSteps(int steps) { this.steps = steps; }
public int getSteps() { return steps; }
public List<Map<String, Object>> getStepsData() { return stepsData; }
}

View File

@@ -41,6 +41,7 @@ public class SeniorAssistant {
* @param args i possibili argomenti da passare al programma
*/
public static void main(String[] args) {
//TODO magari aggiungere un arg con la path per la musica in modo che si possa ampliare in futuro
VariousThreads threads = new VariousThreads(); // this should be the first action of the main
Map<String, String> arguments = getArgsMap(args);
@@ -65,22 +66,24 @@ public class SeniorAssistant {
LOG.warn(e.getMessage());
}
// Lo dichiaro qui, cosi' anche se non ci si puo' collegare al fitbit si puo comunque comandare le luci
Fitbit fitbit=null;
try {
LOG.info("Connessione al Fitbit, ignorare eventuale errore per setPermissionsToOwnerOnly...");
Fitbit fitbit = new Fitbit();
fitbit = new Fitbit();
LOG.info("Connessione al database...");
Database database = remoteDbUser == null ? new LocalDB() : new RemoteDB(remoteDbUser);
threads.startInsertData(database, fitbit);
threads.startHueControlledByHeartBeat(lights, fitbit, database);
threads.startCheckSteps(fitbit);
threads.startCheckSteps(database);
} catch (Exception e) {
LOG.warn("Non e' stato possibile collegarsi al fitbit");
e.printStackTrace();
}
threads.startWebhook(lights);
threads.startWebhook(lights, fitbit);
} catch (Exception e) {
LOG.error(e.getMessage());
}
@@ -88,19 +91,19 @@ public class SeniorAssistant {
}
/*
TODO AUTOMATIC: {D}
AUTOMATIC:
XXX Gestione DB in modo che si aggiorni ogni ora
XXX Gestione luci in modo che la luminosità sia sempre la stessa
XXX Gestione luci a seconda del battito cardiaco
/D/ Ogni X ore/minuti guarda i passi e se sono pochi dillo
XXX Ogni X ore/minuti guarda i passi e se sono pochi dillo
XXX Se i battiti sono troppo bassi/alti avvisare il tizio
TODO USER-INTERACTION {A}
USER-INTERACTION:
/A/ Dati del sonno/battito/passi che l'utente puo' richiedere
XXX Dati del sonno/battito/passi che l'utente puo' richiedere
XXX Gestione luci secondo le esigenze dell'utente ( settare Dialogflow e server + risolvere bug )
XXX Gestione musica tramite comando vocale //TODO mettere a posto dialogflow e inserire qualche canzone
XXX Gestione musica tramite comando vocale //TODO inserire qualche canzone
*/

View File

@@ -5,6 +5,7 @@ import device.Fitbit;
import device.Hue;
import device.Sensor;
import device.fitbitdata.HeartRate;
import device.fitbitdata.Steps;
import support.audio.Audio;
import support.audio.AudioFile;
import support.audio.Musich;
@@ -15,6 +16,9 @@ import java.util.Calendar;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Classe che contiene tutti i thread che servono al programma per funzionare
*/
public class VariousThreads {
/**
@@ -41,16 +45,15 @@ public class VariousThreads {
* Costruttore
*/
public VariousThreads() {
// audio = new AudioFile();
// audio = new AudioFile(); se si vuole solamente questo e non YT
audio = System.getProperty("os.name").startsWith("Windows")? new Musich():new AudioFile();
}
// TODO aggingere il fitbit per la richiesta dei dati
/**
* Fa partire il server Webhook per DialogFlow e continua l'esecuzione
* @param lights le luci che deve controllare
*/
public void startWebhook(final Hue lights) {
public void startWebhook(final Hue lights, final Fitbit fitbit) {
DialogFlowWebHook df = new DialogFlowWebHook();
df.addOnAction("LightsON", (params) -> { lights.turnOn(); cooldown.set(COOLDOWN_IN_MINUTES); return null; });
@@ -87,8 +90,23 @@ public class VariousThreads {
});
df.addOnAction("StopMusic", (params) -> { audio.stop(); return null; });
//TODO aggiungere una azione che faccia in modo di richiedere dei dati in particolare
//TODO aggiungere una azione su DialogFlow che riconosca di impostare una playlist (Rilassante, Antica...)
// TODO GIOVEDI aggiungere un orario magari? se no va bene cosi
df.addOnAction("ReqHearthbeat", (params) -> {
double rate = fitbit.getHeartRate(60);
return "Il battito medio dell'ultima ora e' di "+rate;
});
df.addOnAction("ReqSteps", (params) -> {
int steps = fitbit.getSteps();
return "I passi fatti oggi sono "+steps;
});
df.addOnAction("ReqDistance", (params) -> {
double steps = fitbit.getSteps();
return String.format("Oggi hai percorso circa %.2f kilometri", steps/2000);
});
df.addOnAction("ReqSleep", (params) -> {
long sleep = fitbit.getHoursSleep();
return String.format("Oggi hai dormito per %.2f ore", (double)sleep/3600000);
});
df.startServer();
SeniorAssistant.LOG.info("Webhook partito");
@@ -134,7 +152,7 @@ public class VariousThreads {
calculateBrightFactor(
calendar.get(Calendar.HOUR_OF_DAY),
calendar.get(Calendar.MINUTE),
sensor.getBrightnessLevel()/10,
sensor.getBrightnessLevel(),
minBrightness
);
@@ -156,6 +174,7 @@ public class VariousThreads {
public void startHueControlledByHeartBeat(final Hue lights, final Fitbit fitbit, final Database database) {
final int minutes = 30;
final int delta = 15;
final Audio audio = new AudioFile();
Thread thread = getThreadStartingEach(new Runnable() {
@Override
public synchronized void run() {
@@ -177,15 +196,16 @@ public class VariousThreads {
}
average = count!=0? sum/count:0;
//TODO impostare azioni anche di {E}
//TODO avvisare con una voce registrata? far partire musica rilassante?
double rateNow = fitbit.getHeartRate(minutes);
if ((rateNow-average) >= delta )
if (Math.abs(rateNow-average) > delta ) {
lights.decreaseBrightness();
//avvisare con una voce registrata?
else if ((rateNow-average) <= -delta)
//alzare le luci?
//avvisare con una voce registrata?
;
audio.play("Tullio.wav");
}
else if (Math.abs(rateNow-average) < delta) {
lights.increaseBrightness();
audio.play("Tullio.wav");
}
}
}, minutes, "lights-with-heartbeat");
@@ -193,17 +213,49 @@ public class VariousThreads {
SeniorAssistant.LOG.info("Thread per il controllo delle luci tramite il battito cardiaco partito");
}
// TODO Ad una certa ora guarda i passi e se sono pochi dillo
/**
* Controlla che ad una certa ora si siano fatti abbastanza passi, ed in caso contrario avvisa tramite un messaggio vocale.<br>
* E' possibile trasformarlo in controlla ogni X se si sono fatti dei movimenti o meno.
* @param fitbit da dove vediamo se si sono fatti abbastanza passi
* @param database da dove vediamo se si sono fatti abbastanza passi
*/
public void startCheckSteps(final Fitbit fitbit) {
// trovare un orario (magari inserirlo tramite arg)
// a quell'ora controllare i passi fatti durante la giornata
// se pochi mandare un avviso tramite dialogFlow(?)
// (secondo me si puo' evitare)
public void startCheckSteps(final Database database) {
final int minute = 24 * 60; // ogni ventiquattro ore circa
final int norm = 4500;
final int delta = 1500; // average steps for 60 year old -> 3.500-5.500 or so they say
final Audio audio = new AudioFile();
// ma la domanda e': ad una certa ora o ad ogni X ore?
// AD UNA DETERMINATA ORA
Thread thread = getThreadStartingAt(new Runnable() {
@Override
public synchronized void run() {
List<Steps> list = database.getStepDataOfLast(1);
double sum=0;
int size = list.size();
for(Steps steps: list)
sum += steps.getSteps();
final long average = size!=0? (long)(sum/size):0;
/* Con normale dettata dal tizio e average e' il primo risultato della lista
List<Steps> list = database.getStepDataOfLast(15);
//for
final long norm = size!=0? (long)(sum/size):0;
final long average = size!=0? list.get(0).getSteps():0;
*/
//TODO avvisare con una voce registrata?
if (Math.abs(norm-average) > delta )
audio.play("Tullio.wav");
else if (Math.abs(norm-average) < delta)
audio.play("Tullio.wav");
}
}, 20, "checking-steps");
thread.start();
}
@@ -235,6 +287,42 @@ public class VariousThreads {
return maxIntensity-sensorBright;
}
/**
* Restuisce un thread che se fatto partire, esegue il runnable in un sub-thread alll'ora indicata ogni giorno<br>
* Il sotto thread lanciato avra' lo stesso nome, ma con un trattino e la data di lancio a seguito<br>
* Se il thread viene interrotto non fa piu' partire il runnable e si ferma
* @param runnable il runnable da lanciare
* @param hour l'ora a cui far partire il thread, se negativa o maggiore di 23 ritorna null
* @param threadName il nome da dare al thread
*/
public static Thread getThreadStartingAt(final Runnable runnable, final int hour, String threadName) {
if(hour<0 || hour>23)
return null;
return new Thread(new Runnable() {
@Override
public synchronized void run() {
boolean notInterrupted = true;
Calendar calendar = Calendar.getInstance();
do {
try {
double hourCalculated = calendar.get(Calendar.HOUR_OF_DAY)+((double)calendar.get(Calendar.MINUTE)/60);
double hourToWait = hour-hourCalculated;
if(hourToWait<0)
hourToWait += 24;
wait((long)(hourToWait * 60 * MILLISEC_IN_MINUTE));
Thread thread = new Thread(runnable, threadName + "-" + new Timestamp(System.currentTimeMillis()));
thread.start();
} catch (Exception e) {
e.printStackTrace();
notInterrupted = false;
}
} while (notInterrupted);
}
});
}
/**
* Restuisce un thread che se fatto partire, esegue il runnable in un sub-thread ogni X minuti<br>
* Il sotto thread lanciato avra' lo stesso nome, ma con un trattino e la data di lancio a seguito<br>
@@ -243,7 +331,7 @@ public class VariousThreads {
* @param minutes i minuti da aspettare, se negativi o 0 ritorna null
* @param threadName il nome da dare al thread
*/
public static Thread getThreadStartingEach(final Runnable runnable, int minutes, String threadName) {
public static Thread getThreadStartingEach(final Runnable runnable, final int minutes, String threadName) {
if(minutes<1)
return null;

View File

@@ -26,7 +26,7 @@ public class AuthFitbit {
/**
* Un logger per rendere le cose semplici in caso di casini
*/
private static final Logger LOG = LoggerFactory.getLogger("Fitbit Response");
private static final Logger LOG = LoggerFactory.getLogger("Fitbit Auth");
/**
* Un mapper per trasformare i json in mappe.
@@ -132,7 +132,7 @@ public class AuthFitbit {
String content = response.parseAsString();
response.disconnect();
LOG.info("Recived: " + content);
LOG.debug("Recived: " + content);
return content;
}
@@ -150,7 +150,7 @@ public class AuthFitbit {
*/
public <O> O run(String url, Class<O> returnClass) throws IOException {
O ret = MAPPER.readValue(this.run(url), returnClass);
LOG.info("Saved in class: " + JSON_FACTORY.toString(ret));
LOG.debug("Saved in class: " + JSON_FACTORY.toString(ret));
return ret;
/**/

View File

@@ -24,7 +24,7 @@ public class AudioFile implements Audio {
/**
* L'ultimo audio fatto partire
*/
private AudioStream lastIn = null;
private static AudioStream lastIn = null;
/**
* Serve per crearsi una mapp di tutte le canzoni

View File

@@ -3,13 +3,13 @@ package support.database;
import device.Fitbit;
import device.fitbitdata.HeartRate;
import device.fitbitdata.Sleep;
import device.fitbitdata.Steps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import static main.VariousThreads.MILLISEC_IN_MINUTE;
import static main.VariousThreads.getThreadStartingEach;
import static main.VariousThreads.*;
public interface Database {
@@ -53,6 +53,13 @@ public interface Database {
*/
List<HeartRate> getHeartDataOfLast(int days);
/**
* Riceve i dati dei passi dal giorno selezionato fino ad oggi
* @param days quanti giorni devono esser considerati
* @return una lista dei passifatti negli ultimi X giorni (ordinati da oggi al giorno X)
*/
List<Steps> getStepDataOfLast(int days);
/**
* Prendi il Thread che automaticamente gestisce l'inserimento dei dati orari (per ora solo il battito cardiaco)<br>
* Se per caso c'e' un fallimento riprova ad inserire i dati ogni x minuti, indicati dal terzo parametro<br>
@@ -65,19 +72,20 @@ public interface Database {
Runnable runnable = new Runnable() {
@Override
public synchronized void run() {
LOG.info("Aggiornamento orario iniziato");
try {
boolean retry;
long now = System.currentTimeMillis();
double heartRate = 30;//fitbit.getHeartRate(60);
double heartRate = fitbit.getHeartRate(60);
int steps = fitbit.getSteps(1);
do {
retry = !database.updateHeart(now, heartRate);
LOG.info("Aggiornamento " + (!retry ? "riuscito" : "fallito, riprovo fra " + retryMinutes + " minuti"));
retry = retry && !database.updateSteps(now, steps);
LOG.info("Aggiornamento orario " + (!retry ? "riuscito" : "fallito, riprovo fra " + retryMinutes + " minuti"));
if (retry)
wait(retryMinutes * MILLISEC_IN_MINUTE);
} while(retry);
} catch (Exception e) {
LOG.warn("Aggiornamento interrotto");
LOG.warn("Aggiornamento orario interrotto");
}
}
};
@@ -86,7 +94,7 @@ public interface Database {
}
/**
* Prendi il Thread che automaticamente gestisce l'inserimento dei dati giornalieri<br>
* Prendi il Thread che automaticamente gestisce l'inserimento dei dati giornalieri, esso fara' i tentativi alle 23<br>
* Se per caso c'e' un fallimento riprova ad inserire i dati ogni x minuti, indicati dal terzo parametro<br>
* @param database il database in cui inserirlo
* @param fitbit la classe che contiene i dati aggiornati
@@ -97,27 +105,23 @@ public interface Database {
Runnable runnable = new Runnable() {
@Override
public synchronized void run() {
LOG.info("Aggiornamento giornaliero iniziato");
try {
boolean retry;
long steps = fitbit.getSteps();
List<Sleep.SleepData> sleepDatas = fitbit.getDetailedSleep();
long now = System.currentTimeMillis();
boolean retry = !sleepDatas.isEmpty();
do {
retry = !database.updateSteps(now, steps);
for (Sleep.SleepData data : sleepDatas)
retry = retry && !database.updateSleep(data.start_date, data.duration);
LOG.info("Aggiornamento " + (!retry ? "riuscito" : "fallito, riprovo fra " + retryMinutes + " minuti"));
LOG.info("Aggiornamento giornaliero" + (!retry ? "riuscito" : "fallito, riprovo fra " + retryMinutes + " minuti"));
if (retry)
wait(retryMinutes * MILLISEC_IN_MINUTE);
} while (retry);
} catch (Exception e) {
LOG.warn("Aggiornamento interrotto");
LOG.warn("Aggiornamento giornaliero interrotto");
}
}
};
return getThreadStartingEach(runnable, 24*60, "update-daily-data");
return getThreadStartingAt(runnable, 23, "update-daily-data");
}
}

View File

@@ -1,6 +1,7 @@
package support.database;
import device.fitbitdata.HeartRate;
import device.fitbitdata.Steps;
import java.sql.*;
import java.util.LinkedList;
@@ -112,6 +113,29 @@ public class LocalDB implements Database {
return null;
}
@Override
public List<Steps> getStepDataOfLast(int days) {
try {
int dayToSubtract = 15;
long time = System.currentTimeMillis() - (dayToSubtract * 24 * 60 * 1000);
ResultSet result = conn.createStatement().executeQuery("SELECT * FROM steps WHERE day>='" + new Timestamp(time) + "'");
List<Steps> list = new LinkedList<>();
while(result.next()) {
Steps steps = new Steps();
steps.setSteps(result.getInt("rate"));
steps.setDate(result.getDate("day").getTime());
list.add(steps);
}
return list;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
private boolean query(String sql) {
try {
conn.createStatement().execute(sql);

View File

@@ -3,6 +3,7 @@ package support.database;
import ai.api.GsonFactory;
import com.google.gson.Gson;
import device.fitbitdata.HeartRate;
import device.fitbitdata.Steps;
import support.Rest;
import java.sql.Timestamp;
@@ -73,13 +74,7 @@ public class RemoteDB implements Database {
@Override
public List<HeartRate> getHeartDataOfLast(int days) {
try {
Calendar ago = Calendar.getInstance();
ago.setTimeInMillis(System.currentTimeMillis());
ago.add(Calendar.DATE, -days);
DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
String url = base_url+"heartbeat/"+username+"/"+format.format(ago.getTime())+"/today/";
String url = base_url+"heartbeat/"+username+"/last/"+(days*24);
Map<String, List<Map<String, Object>>> map = (Map<String, List<Map<String, Object>>>) Rest.get(url);
List<HeartRate> list = new ArrayList<>(map.get("list").size());
@@ -97,6 +92,27 @@ public class RemoteDB implements Database {
}
}
@Override
public List<Steps> getStepDataOfLast(int days) {
try {
String url = base_url+"step/"+username+"/last/"+(days*24);
Map<String, List<Map<String, Object>>> map = (Map<String, List<Map<String, Object>>>) Rest.get(url);
List<Steps> list = new ArrayList<>(map.get("list").size());
for(Map<String, Object> data: map.get("list")) {
Steps steps = new Steps();
steps.setSteps((int)data.get("value"));
steps.setDate(STD_FORMAT.parse((String)data.get("time")).getTime());
list.add(steps);
}
return list;
} catch (ParseException e) {
LOG.error(e.getMessage());
return null;
}
}
/**
* Serve ad inviare una richiesta PUT per aggiornare i dati
* @param type il tipo di dato che deve esser aggiornato

View File

@@ -2,9 +2,10 @@ package test;
import device.Fitbit;
import org.junit.Test;
import support.Rest;
public class TestFitbit {
@Test
public void test01() throws Exception {
Fitbit fitBit = new Fitbit();
@@ -14,5 +15,13 @@ public class TestFitbit {
System.out.println("Today's hours of sleep: "+fitBit.getHoursSleep());
System.out.println("Today's steps: "+fitBit.getSteps());
System.out.println("Fine.");
Rest.get("https://api.fitbit.com/1/user/-/activities/steps/date/today/1d.json");
}
@Test
public void test02() throws Exception {
Fitbit fitbit = new Fitbit();
System.out.println(fitbit.getSteps(60));
}
}

View File

@@ -1,6 +1,5 @@
package test;
import ai.api.GsonFactory;
import device.Hue;
import main.VariousThreads;
import org.junit.Before;
@@ -51,12 +50,10 @@ public class TestLights {
@Test
synchronized public void testColor() throws InterruptedException {
// change colors
for (int i=0; i<=360; i++) {
double radian = (0.0174533*i);
double x = Math.cos(radian);
double y = Math.sin(radian);
lights.setState("xy", GsonFactory.getDefaultFactory().getGson().toJson(new Double[]{x, y}));
String[] colors = {"rosso", "giallo", "verde", "blu", "bianco", "azzurro", "arancio"};
for (String color : colors) {
lights.changeColor(color);
this.wait(TIMEOUT);
}
}

View File

@@ -34,6 +34,18 @@ public class TestMusich {
audio.stop();
}
@Test
public void test3() {
AudioFile audio = new AudioFile();
AudioFile audio2 = new AudioFile();
audio.play("Tullio.wav");
waitAndPrint(3);
audio2.play("Tullio.wav");
waitAndPrint(10);
audio.stop();
audio2.stop();
}
public void waitAndPrint(Integer seconds) {
if(seconds != null) synchronized (seconds) {
try {