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:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
*/
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
/**/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user