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:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -29,6 +29,7 @@ hs_err_pid*
|
||||
.idea/*.xml
|
||||
.gradle/
|
||||
.iml
|
||||
.db
|
||||
|
||||
# eclipse things #
|
||||
.classpath
|
||||
|
||||
@@ -7,10 +7,12 @@ import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import spark.Spark;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static spark.Spark.get;
|
||||
import static spark.Spark.post;
|
||||
|
||||
/**
|
||||
@@ -21,7 +23,12 @@ public class DialogFlowWebHook {
|
||||
/**
|
||||
* Un logger per vedere le cose piu' easy
|
||||
*/
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DialogFlowWebHook.class);
|
||||
|
||||
/**
|
||||
* Stringa che viene usata se l'azione esiste ma lancia un qualche tipo di errore
|
||||
*/
|
||||
public static final String ACTION_ERROR = "Purtroppo chi mi ha programmato e' un pirla, non posso fare cio' che hai chiesto";
|
||||
|
||||
/**
|
||||
* Errore che viene mostrato all'utente se l'azione inviata non corrisponde a nessuna di quelle inserite
|
||||
@@ -33,67 +40,89 @@ public class DialogFlowWebHook {
|
||||
*/
|
||||
public final String path;
|
||||
|
||||
/**
|
||||
* La porta in cui il server ascoltera'
|
||||
*/
|
||||
public final int port;
|
||||
|
||||
/**
|
||||
* Mappa che contiene tutte le azioni e il loro ID
|
||||
*/
|
||||
private final Map<String, Action> actions;
|
||||
|
||||
/**
|
||||
* Crea una classe vuota per un server che risponde lle chiamate di Dialog-Flow.
|
||||
* La path viene impostata di default a "/"
|
||||
* Crea una classe vuota per un server che risponde alle chiamate di Dialog-Flow.
|
||||
* La path viene impostata di default a "/" e la porta a 4567
|
||||
*/
|
||||
public DialogFlowWebHook() {
|
||||
this("/");
|
||||
}
|
||||
public DialogFlowWebHook() { this("/", 4567); }
|
||||
|
||||
/**
|
||||
* Crea una classe vuota per un server che risponde lle chiamate di Dialog-Flow.
|
||||
* Crea una classe vuota per un server che risponde alle chiamate di Dialog-Flow.
|
||||
* @param path il percorso dopo l'url inidicato nel WebHook di Dialog-Flow
|
||||
* @param port la porta da cui il Webhoook ascolta (se inserito numero negativo ascolta di default sulla porta 4567)
|
||||
*/
|
||||
public DialogFlowWebHook(String path) {
|
||||
public DialogFlowWebHook(String path, int port) {
|
||||
this.path = path;
|
||||
this.port = port>0? port:4567;
|
||||
this.actions = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggiunge un'azione ad una specifica richiesta di Dialog-Flow
|
||||
* @param actionId il nome dell'azione che viene passata da Dialog-Flow
|
||||
* @param action l'azione da fare (usare lambda)
|
||||
* @param action l'azione da fare (e' consigliato usare le espressioni lambda)
|
||||
*/
|
||||
public void addOnAction(String actionId, Action action) {
|
||||
this.actions.put(actionId, action);
|
||||
}
|
||||
public void addOnAction(String actionId, Action action) { this.actions.put(actionId, action); }
|
||||
|
||||
/**
|
||||
* Fa partire il server per accettare richieste da Dialog-Flow.
|
||||
* Ogni richiesta viene esaminata e fatta coincidere con una azione specificata precedentemente.
|
||||
* Se nessuna azione viene riscontrata, viene inviato un errore, rimuovendo i messaggi
|
||||
* Fa partire il server per accettare richieste da Dialog-Flow ascoltando connessioni in post.<br>
|
||||
* Ogni richiesta viene esaminata e fatta coincidere con un'azione specificata precedentemente.<br>
|
||||
* Se nessuna azione viene riscontrata, viene inviato un errore, rimuovendo i messaggi<br>
|
||||
* Inoltre aggiunge un'interfaccia in get che riguarda un iframe di dialogflow
|
||||
*/
|
||||
public void startServer() { // todo add param port? Spark.port(num);
|
||||
public void startServer() {
|
||||
Spark.port(this.port);
|
||||
Gson gson = GsonFactory.getDefaultFactory().getGson();
|
||||
post(this.path, (request, response) -> {
|
||||
Fulfillment output = new Fulfillment();
|
||||
AIResponse input = gson.fromJson(request.body(), AIResponse.class);
|
||||
|
||||
String text = null;
|
||||
String inputAction = input.getResult().getAction();
|
||||
Map<String, JsonElement> inputParam = input.getResult().getParameters();
|
||||
String text;
|
||||
try {
|
||||
log.info("AZIONE: "+input.getResult().getAction());
|
||||
Action action = actions.get(input.getResult().getAction());
|
||||
text = action.doAction(input.getResult().getParameters());
|
||||
LOG.debug("AZIONE: "+ inputAction + ", PARAMS: " + inputParam);
|
||||
Action action = actions.get(inputAction);
|
||||
try {
|
||||
text = action.doAction(inputParam);
|
||||
} catch (NullPointerException e) {
|
||||
LOG.warn("AZIONE FALLITA: "+ inputAction);
|
||||
text = ACTION_ERROR;
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
log.info("NESSUNA AZIONE TROVATA");
|
||||
LOG.error("NESSUNA AZIONE TROVATA: "+ inputAction);
|
||||
text = ERROR;
|
||||
}
|
||||
|
||||
if(text != null) {
|
||||
log.info(text);
|
||||
output.setDisplayText(text);
|
||||
output.setSpeech(text);
|
||||
}
|
||||
if(text == null)
|
||||
text = input.getResult().getFulfillment().getSpeech();
|
||||
|
||||
LOG.debug("RISPOSTA: " + text);
|
||||
output.setDisplayText(text);
|
||||
output.setSpeech(text);
|
||||
|
||||
response.type("application/json");
|
||||
return output;
|
||||
}, gson::toJson);
|
||||
|
||||
get(this.path, (request, response) -> {
|
||||
return "<iframe\n" +
|
||||
" allow=\"microphone;\"\n" +
|
||||
" width=\"350\"\n" +
|
||||
" height=\"430\"\n" +
|
||||
" src=\"https://console.dialogflow.com/api-client/demo/embedded/SeniorAssistant\">\n" +
|
||||
"</iframe>";
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,7 +133,7 @@ public class DialogFlowWebHook {
|
||||
* Fai l'azione desiderata.
|
||||
* Se ritorna una stringa allora il testo viene cambiato. Se ritorna null non cambia il testo
|
||||
*
|
||||
* @param params a map containing all the parameters passed form the request
|
||||
* @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
|
||||
*/
|
||||
String doAction(Map<String, JsonElement> params);
|
||||
|
||||
@@ -20,25 +20,29 @@ public class Fitbit {
|
||||
* Url da dove si possono prendere i dati dai vari dispositivi fitbit
|
||||
*/
|
||||
public static final String BASIC_URL = "https://api.fitbit.com/";
|
||||
|
||||
/**
|
||||
* Utente del fitbit<br>
|
||||
* In questo caso e' universale e prende l'utente che e' attualmente loggato
|
||||
*/
|
||||
public static final String USER = "/user/-/";
|
||||
|
||||
/**
|
||||
* Un minuto in millisecondi
|
||||
*/
|
||||
private static final long MINUTE = 60000; /* 5 minutes in millisec */
|
||||
private static final long MINUTE = 60000;
|
||||
|
||||
/**
|
||||
* L'oauth per l'account fitbit
|
||||
*/
|
||||
private final AuthFitbit auth;
|
||||
|
||||
/**
|
||||
* Una mappa contenente le ultime classi usate nelle richieste effettuate<br>
|
||||
* Una sorta di cache
|
||||
*/
|
||||
private final Map<Class<?>, Long> latestRequest = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Un calendario in modo da sapere la data per i dati
|
||||
*/
|
||||
@@ -48,26 +52,25 @@ public class Fitbit {
|
||||
* La classe per sapere i dati sul battito cardiaco
|
||||
*/
|
||||
private HeartRate heart = null;
|
||||
|
||||
/**
|
||||
* La classe per sapere i dati sul sonno
|
||||
*/
|
||||
private Sleep sleep = null;
|
||||
|
||||
/**
|
||||
* La classe per sapere i dati sui passi effettuati
|
||||
*/
|
||||
private Steps steps = null;
|
||||
|
||||
/**
|
||||
* Crea una istanza di fitbit<br>
|
||||
* Crea un'istanza di fitbit<br>
|
||||
* Se l'utente non ha ancora accettato i dati richiesti o l'utente non e'
|
||||
* loggato,<br>
|
||||
* verra' aperto il browser in modo che si possano inserire i dati
|
||||
* loggato, verra' aperto il browser in modo che si possano inserire i dati
|
||||
*
|
||||
* @throws Exception Nel caso qualunque cosa andasse storta (vedi messaggio)
|
||||
*/
|
||||
public Fitbit() throws Exception {
|
||||
this.auth = new AuthFitbit();
|
||||
}
|
||||
public Fitbit() throws Exception { this.auth = new AuthFitbit(); }
|
||||
|
||||
/**
|
||||
* Ricevi i passi che l'utente ha effettuato nell'ultimo giorno
|
||||
@@ -87,15 +90,13 @@ public class Fitbit {
|
||||
* @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() throws IOException {
|
||||
return getHeartRate(15);
|
||||
}
|
||||
public synchronized double getHeartRate() throws IOException { return getHeartRate(15); }
|
||||
|
||||
/**
|
||||
* Ricevi il battito cardiaco dell'utente<br>
|
||||
* Il risultato e' una media del battito che l'utente ha avuto negli ultimi minuti
|
||||
*
|
||||
* @param lastMinutes fino a quanti minuti bisogna tenere conto (positivi se no ritorno -1)
|
||||
* @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
|
||||
*/
|
||||
@@ -141,7 +142,7 @@ public class Fitbit {
|
||||
}
|
||||
|
||||
/**
|
||||
* Semplice funzione che controlla che si possa fare l'update o meno di una specifica classe<br>
|
||||
* Semplice funzione che controlla che si possa fare l'update o meno di una specifica classe.<br>
|
||||
* Se e' possibile fare l'update viene mandata una run all'url selezionato e viene ritornata la variabile aggiornata<br>
|
||||
* Altrimenti viene ritornata la variabile passata
|
||||
*
|
||||
@@ -150,7 +151,7 @@ public class Fitbit {
|
||||
* @param url l'url da cui prende i dati aggiornati
|
||||
* @return la variabile aggiornata
|
||||
*/
|
||||
private <T> T update(Class<T> varClass, T variable, String url) throws IOException {
|
||||
private synchronized <T> T update(Class<T> varClass, T variable, String url) throws IOException {
|
||||
try {
|
||||
long current = System.currentTimeMillis();
|
||||
long latest = latestRequest.get(varClass);
|
||||
|
||||
@@ -22,36 +22,36 @@ public class Hue {
|
||||
*/
|
||||
public static final Map<String, Double[]> COLORS = new HashMap<>();
|
||||
|
||||
// todo set right colors
|
||||
static {
|
||||
COLORS.put("giallo", new Double[]{0.55, 0.45});
|
||||
COLORS.put("rosso", new Double[]{0.7, 0.25});
|
||||
COLORS.put("verde", new Double[]{0.15, 0.65});
|
||||
COLORS.put("blu", new Double[]{0.0, 0.0});
|
||||
COLORS.put("rosa", new Double[]{0.45, 0.15});
|
||||
COLORS.put("viola", new Double[]{0.25, .1});
|
||||
COLORS.put("azzurro", new Double[]{0.15, 0.25});
|
||||
COLORS.put("arancione", new Double[]{0.63, 0.35});
|
||||
//COLORS.put("nero", new Double[]{1.0, 1.0});
|
||||
COLORS.put("bianco", new Double[]{0.35, 0.3});
|
||||
}
|
||||
|
||||
//private String baseURL = "192.168.0.2";
|
||||
//private String username = "C0vPwqjJZo5Jt9Oe5HgO6sBFFMxgoR532IxFoGmx";
|
||||
/**
|
||||
* L'url in cui si possono trovare le luci
|
||||
*/
|
||||
private String lightsURL; // = baseURL+"/api/"+username+"/lights/";
|
||||
private final String lightsURL;
|
||||
|
||||
/**
|
||||
* Tutte le luci che sono state registrate dall'url
|
||||
*/
|
||||
private Map<String, ?> allLights;
|
||||
private final Map<String, Map<String, Object>> allLights;
|
||||
|
||||
/**
|
||||
* L'ultima luminosita' impostata
|
||||
*/
|
||||
private int brightness = 0;
|
||||
private double brightness = 0;
|
||||
|
||||
/**
|
||||
* Riempimento della mappa con i vari colori
|
||||
*/
|
||||
static { // todo set right colors (in the simulation they are off, maybe in reality are ok)
|
||||
COLORS.put("giall[oae]", new Double[]{0.475, 0.475});
|
||||
COLORS.put("ross[oae]", new Double[]{0.7, 0.25});
|
||||
COLORS.put("verd[ei]", new Double[]{0.1, 0.55});
|
||||
COLORS.put("blu", new Double[]{0.15, 0.175});
|
||||
COLORS.put("rosa", new Double[]{0.45, 0.275});
|
||||
COLORS.put("viola", new Double[]{0.25, 0.1});
|
||||
COLORS.put("azzurr[oae]", new Double[]{0.15, 0.25});
|
||||
COLORS.put("arancio(ne|ni)?", new Double[]{0.6, 0.35});
|
||||
//COLORS.put("nero", new Double[]{1.0, 1.0});
|
||||
COLORS.put("bianc(o|a|he)", new Double[]{0.3, 0.25});
|
||||
}
|
||||
|
||||
/**
|
||||
* Cerca le luci Philips Hue a ll'indirizzo <a href="http://172.30.1.138/api/C0vPwqjJZo5Jt9Oe5HgO6sBFFMxgoR532IxFoGmx/lights/">http://172.30.1.138/api/C0vPwqjJZo5Jt9Oe5HgO6sBFFMxgoR532IxFoGmx/lights/</a>
|
||||
@@ -61,23 +61,31 @@ public class Hue {
|
||||
}
|
||||
|
||||
/**
|
||||
* Cerca le luci Philips Hue nell'indirizzo specificato e con l'utente specificato
|
||||
* @param ip l'indirizzo IP
|
||||
* Cerca le luci Philips Hue nell'indirizzo specificato e con l'utente specificato.<br>
|
||||
* Una volta trovate le luci le setta tutte alla stessa luminosita' e allo stesso colore<br>
|
||||
* (per ora fa una media e poi assegna il valore risultante a tutte)
|
||||
* @param ip l'indirizzo IP (seguito dalla porta se e' diversa dalla solita 8000)
|
||||
* @param user l'utente
|
||||
*/
|
||||
public Hue(String ip, String user) {
|
||||
this("http://" + ip + "/api/" + user + "/lights/");
|
||||
}
|
||||
lightsURL = "http://" + ip + "/api/" + user + "/lights/";
|
||||
allLights = (Map<String, Map<String, Object>>)Rest.get(lightsURL);
|
||||
|
||||
/**
|
||||
* Inizializza la classe cercando tutte le luci all'indirizzo url specificato
|
||||
*
|
||||
* @param url l'indirizzo da inserire delle luci Hue
|
||||
*/
|
||||
public Hue (String url) {
|
||||
lightsURL = url;
|
||||
allLights = Rest.get(lightsURL);
|
||||
// Todo brightness initial, maybe by default 50% or 75% of the total
|
||||
if(allLights.size() != 0) {
|
||||
double bri = 0;
|
||||
double hue = 0;
|
||||
for (String name: allLights.keySet()) {
|
||||
Map<String, Object> state = (Map<String, Object>)allLights.get(name).get("state");
|
||||
bri += (Double) state.get("bri");
|
||||
hue += (Double) state.get("hue");
|
||||
}
|
||||
bri = bri/allLights.size();
|
||||
hue = hue/allLights.size();
|
||||
setState("bri", String.valueOf(bri));
|
||||
setState("hue", String.valueOf(hue));
|
||||
|
||||
brightness = (bri*MAX_BRIGHTNESS)/100;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,9 +93,7 @@ public class Hue {
|
||||
*
|
||||
* @return l'insieme dei nomi delle luci
|
||||
*/
|
||||
public Set<String> getNameLights() {
|
||||
return allLights.keySet();
|
||||
}
|
||||
public Set<String> getNameLights() { return allLights.keySet(); }
|
||||
|
||||
/**
|
||||
* Rimuove dal controllo tutte le luci che hanno il nome uguale ad uno contenuto nell'insieme passato
|
||||
@@ -102,95 +108,90 @@ public class Hue {
|
||||
/**
|
||||
* Accende tutte le luci controllate
|
||||
*/
|
||||
public void turnOn() {
|
||||
setState("on", "true");
|
||||
}
|
||||
public void turnOn() { setState("on", "true"); }
|
||||
|
||||
/**
|
||||
* Spegne tutte le luci controllate
|
||||
*/
|
||||
public void turnOff() {
|
||||
setState("on", "false");
|
||||
}
|
||||
public void turnOff() { setState("on", "false"); }
|
||||
|
||||
/**
|
||||
* Ritorna la liminosita' attuale delle luci controllate
|
||||
* @return
|
||||
*/
|
||||
public int getCurrentBrightness() {
|
||||
return brightness;
|
||||
}
|
||||
public double getCurrentBrightness() { return brightness; }
|
||||
|
||||
/**
|
||||
* Modifica la luminosita' delle luci a seconda del valore inserito
|
||||
* @param num la luminosita' che si vuole
|
||||
* @param num la luminosita' che si vuole da (0 a 100)
|
||||
*/
|
||||
public void setBrightness(int num) {
|
||||
public void setBrightness(double num) {
|
||||
if (num<0)
|
||||
num=0;
|
||||
setState("bri", String.valueOf(num));
|
||||
else if (num>100)
|
||||
num=100;
|
||||
|
||||
setState("bri", String.valueOf( (num*MAX_BRIGHTNESS)/100) );
|
||||
brightness = num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dinuisce la luminosita' delle luci controllate della percentuale che viene passata
|
||||
* @param percentage la percentuale di diminuzione
|
||||
* Aumenta la luminosita' delle luci controllate della percentuale che viene passata
|
||||
* @param percentage la percentuale di aumento della luminosita'
|
||||
*/
|
||||
public void increaseBrightness(int percentage) {
|
||||
public void increaseBrightness(double percentage) {
|
||||
if (percentage<0)
|
||||
percentage = 0;
|
||||
else if (percentage>100)
|
||||
percentage = 100;
|
||||
setBrightness(brightness + (percentage*MAX_BRIGHTNESS)/100);
|
||||
setBrightness(brightness + percentage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Aumenta la luminosita' delle luci controllate del 10%
|
||||
* Aumenta la luminosita' delle luci controllate del 15%
|
||||
*/
|
||||
public void increaseBrightness() {
|
||||
increaseBrightness(10);
|
||||
}
|
||||
public void increaseBrightness() { increaseBrightness(15); }
|
||||
|
||||
/**
|
||||
* Dinuisce la luminosita' delle luci controllate della percentuale che viene passata
|
||||
* @param percentage la percentuale di diminuzione
|
||||
* @param percentage la percentuale di diminuzione della luminosita'
|
||||
*/
|
||||
public void decreaseBrightness(int percentage) {
|
||||
if (percentage<0)
|
||||
percentage = 0;
|
||||
else if (percentage>100)
|
||||
percentage = 100;
|
||||
setBrightness(brightness - (percentage*MAX_BRIGHTNESS)/100);
|
||||
setBrightness(brightness - percentage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dinuisce la luminosita' delle luci controllate del 10%
|
||||
* Dinuisce la luminosita' delle luci controllate del 15%
|
||||
*/
|
||||
public void decreaseBrightness() {
|
||||
decreaseBrightness(10);
|
||||
}
|
||||
public void decreaseBrightness() { decreaseBrightness(15); }
|
||||
|
||||
public void changeColor(String colorName) {
|
||||
String hueColor = GsonFactory.getDefaultFactory().getGson().toJson(COLORS.get(colorName));
|
||||
setState("xy", hueColor);
|
||||
for (String regex: COLORS.keySet())
|
||||
if(colorName.matches("(?i)" + regex))
|
||||
setState("xy", GsonFactory.getDefaultFactory().getGson().toJson(COLORS.get(regex)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifica il colore delle luci in modo da fare un bel effetto arcobaleno continuo
|
||||
*/
|
||||
public void colorLoop() {
|
||||
setState("effect", "colorloop");
|
||||
}
|
||||
public void colorLoop() { setState("effect", "colorloop"); }
|
||||
|
||||
/**
|
||||
* Funzione generale per poter utilizzare qualunque valore, ma non funziona<br>
|
||||
* Da testare, visto che mi sembra strano che non funzi...
|
||||
* Da testare, visto che mi sembra strano che non funzi...<br>
|
||||
* e invece funziona.
|
||||
*/
|
||||
public void setState(String attribute, String value){
|
||||
for (String light : allLights.keySet())
|
||||
for (String light : allLights.keySet()) {
|
||||
Map<String, Object> state = (Map<String, Object>)allLights.get(light).get("state");
|
||||
Rest.put(lightsURL + light + "/state",
|
||||
"{ \"" + attribute + "\" : " + value + " }",
|
||||
"application/json");
|
||||
"{ \"" + attribute + "\" : " + value + ", \"transitiontime\": 10 }", // todo check transition
|
||||
"application/json");
|
||||
state.put(attribute, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,10 +11,6 @@ import support.ZWaySimpleCallback;
|
||||
*/
|
||||
public class Sensor {
|
||||
|
||||
/* todo ma serve il LOGGER?
|
||||
private Logger logger = LoggerFactory.getLogger(Sensor.class);
|
||||
*/
|
||||
|
||||
/**
|
||||
* IP del sensore a cui ci si vuole agganciare
|
||||
*/
|
||||
@@ -100,7 +96,8 @@ public class Sensor {
|
||||
device.update();
|
||||
wait(timeout);
|
||||
}
|
||||
/*public boolean IsLowLuminescence(int Luminescence) {
|
||||
/*
|
||||
public boolean IsLowLuminescence(int Luminescence) {
|
||||
if (dev.getProbeType().equalsIgnoreCase("Luminescence"))
|
||||
if (Integer.parseInt(dev.getMetrics().getLevel()) < Luminescence)
|
||||
return true;
|
||||
|
||||
@@ -9,17 +9,9 @@ import java.util.Map;
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class HeartRate {
|
||||
|
||||
private String dateTime;
|
||||
private double average;
|
||||
|
||||
public double getAverage() {
|
||||
return average;
|
||||
}
|
||||
|
||||
@JsonProperty("activities-heart")
|
||||
public void quelloCheVoglio(Map<String, Object>[] activities){
|
||||
dateTime = (String) activities[0].get("dateTime");
|
||||
}
|
||||
public double getAverage() { return average; }
|
||||
|
||||
@JsonProperty("activities-heart-intraday")
|
||||
public void setAverage(Map<String, Object> map) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package device.fitbitdata;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
@@ -48,14 +49,14 @@ public class Sleep {
|
||||
}
|
||||
|
||||
public class SleepData {
|
||||
public final Date start_date;
|
||||
public final Timestamp start_date;
|
||||
public final long duration;
|
||||
public final Date end_date;
|
||||
public final Timestamp end_date;
|
||||
|
||||
public SleepData(Date start_date, long duration) {
|
||||
this.start_date = start_date;
|
||||
this.start_date = new Timestamp(start_date.getTime());
|
||||
this.duration = duration;
|
||||
this.end_date = start_date!=null? new Date(start_date.getTime() + duration):null;
|
||||
this.end_date = start_date!=null? new Timestamp(start_date.getTime() + duration):null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,6 @@ public class Steps {
|
||||
steps = Integer.parseInt(map.get("value"));
|
||||
}
|
||||
|
||||
public int getSteps() {
|
||||
return steps;
|
||||
}
|
||||
public int getSteps() { return steps; }
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
package main;
|
||||
|
||||
import ai.api.GsonFactory;
|
||||
import device.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import support.Database;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
// todo docs
|
||||
/**
|
||||
* Created by 20015159 on 28/08/2018.
|
||||
*/
|
||||
@@ -23,23 +19,22 @@ public class Main {
|
||||
private static Fitbit fitbit;
|
||||
private static Sensor sensor;
|
||||
|
||||
private static Database database;
|
||||
|
||||
/**
|
||||
* Funzione principale, qui si creano tutte le classi che verranno utilizzate.
|
||||
* @param args per ora nulla, ma forse in futuro si potrebbe mettere roba
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
|
||||
// todo setting log level -> useful if you dont need to see a spam of things but not working
|
||||
// System.setProperty(SimpleLogger.DEFAULT_LOG_LEVEL_KEY , SimpleLogger.S);
|
||||
|
||||
LOG.info("Connecting to hue lights");
|
||||
lights = new Hue("localhost:8090", "newdeveloper");
|
||||
lights = new Hue("192.168.1.7:8090", "newdeveloper");
|
||||
|
||||
LOG.info("Connecting to the sensors");
|
||||
sensor = new Sensor();
|
||||
|
||||
try {
|
||||
LOG.info("Connecting to Database");
|
||||
database = Database.getInstance();
|
||||
|
||||
LOG.info("Connecting to Fitbit");
|
||||
fitbit = new Fitbit();
|
||||
|
||||
@@ -56,13 +51,27 @@ public class Main {
|
||||
* Fa partire il server Webhook per DialogFlow e continua l'esecuzione
|
||||
*/
|
||||
private static void startWebhook() {
|
||||
LOG.info("Adding actions to Webhook");
|
||||
DialogFlowWebHook df = new DialogFlowWebHook();
|
||||
|
||||
df.addOnAction("LightsON", (params) -> {lights.turnOn(); return null;});
|
||||
df.addOnAction("LightsOFF", (params) -> {lights.turnOff(); return null;});
|
||||
df.addOnAction("ColorLoop", (params) -> {lights.colorLoop(); return null;});
|
||||
df.addOnAction("ChangeColor", (params) -> {lights.changeColor(params.get("color").getAsString()); return null;});
|
||||
df.addOnAction("SetLights", (params) -> {lights.setBrightness(params.get("intensity").getAsInt()); return null;});
|
||||
df.addOnAction("LightsDOWN", (params) -> {
|
||||
if(params.get("intensity").getAsString().equals(""))
|
||||
lights.decreaseBrightness();
|
||||
else
|
||||
lights.decreaseBrightness(params.get("intensity").getAsInt());
|
||||
return null;
|
||||
});
|
||||
df.addOnAction("LightsUP", (params) -> {
|
||||
if(params.get("intensity").getAsString().equals(""))
|
||||
lights.increaseBrightness();
|
||||
else
|
||||
lights.increaseBrightness(params.get("intensity").getAsInt());
|
||||
return null;
|
||||
});
|
||||
|
||||
LOG.info("Starting Webhook");
|
||||
df.startServer();
|
||||
@@ -72,47 +81,36 @@ public class Main {
|
||||
* Gestione DB in modo che si aggiorni ogni ora
|
||||
*/
|
||||
private static void startInsertData() {
|
||||
LOG.info("Connecting to DB to write fitbit data periodically");
|
||||
try {
|
||||
fitbit.getHoursSleep();
|
||||
|
||||
Database database = Database.getInstance();
|
||||
|
||||
Thread hourlyData = new Thread(database.insertHourlyData(fitbit), "updating-hour-data");
|
||||
Thread dailyData = new Thread(database.insertDailyData(fitbit), "updating-day-data");
|
||||
|
||||
LOG.info("Starting threads for automatic update");
|
||||
hourlyData.start();
|
||||
dailyData.start();
|
||||
LOG.info("Threads started for updating database");
|
||||
} catch (IOException e) {
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public static void main(String[] args) throws Exception {
|
||||
Fitbit fitbit = new Fitbit();
|
||||
Sensor sensor = new Sensor();
|
||||
Hue hue = new Hue();
|
||||
TODO AUTOMATIC: {B}, {C}, {D}, {E}
|
||||
|
||||
while(true) {
|
||||
double heart = fitbit.getHeartRate();
|
||||
int brightness = sensor.getBrightnessLevel();
|
||||
XXX Gestione DB in modo che si aggiorni ogni ora
|
||||
/B/ Gestione luci in modo che la luminosità sia sempre la stessa
|
||||
/C/ Gestione luci a seconda del battito cardiaco
|
||||
/D/ Ad una certa ora guarda i passi e se sono pochi dillo
|
||||
/E/ Se i battiti sono troppo bassi/alti avvisare il tizio
|
||||
|
||||
// AUTOMATIC
|
||||
/X/ Gestione DB in modo che si aggiorni ogni ora
|
||||
// Gestione luci in modo che la luminosità sia sempre la stessa
|
||||
// Gestione luci a seconda del battito cardiaco
|
||||
// Ad una certa ora guarda i passi e se sono pochi dillo
|
||||
// Se i battiti sono troppo bassi/alti avvisare il tizio
|
||||
TODO USER-INTERACTION {A}, {C}
|
||||
|
||||
// USER-INTERACTION
|
||||
// Dati del sonno/battito/passi che l'utente puo' richiedere
|
||||
/X/ Gestione luci secondo le esigenze dell'utente ( settare Dialogflow e server + risolvere bug )
|
||||
// EXTRA Gestione musica tramite comando vocale
|
||||
/A/ Dati del sonno/battito/passi che l'utente puo' richiedere
|
||||
XXX Gestione luci secondo le esigenze dell'utente ( settare Dialogflow e server + risolvere bug )
|
||||
/C/ EXTRA Gestione musica tramite comando vocale
|
||||
|
||||
// Randomly at night heavy metal start
|
||||
}
|
||||
}
|
||||
// Randomly at night heavy metal start
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package oauth;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import ai.api.GsonFactory;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.api.client.auth.oauth2.AuthorizationCodeFlow;
|
||||
import com.google.api.client.auth.oauth2.BearerToken;
|
||||
@@ -16,7 +15,6 @@ import com.google.api.client.http.HttpRequestFactory;
|
||||
import com.google.api.client.http.HttpResponse;
|
||||
import com.google.api.client.http.HttpTransport;
|
||||
import com.google.api.client.http.javanet.NetHttpTransport;
|
||||
import com.google.api.client.json.GenericJson;
|
||||
import com.google.api.client.json.JsonFactory;
|
||||
import com.google.api.client.json.JsonObjectParser;
|
||||
import com.google.api.client.json.jackson2.JacksonFactory;
|
||||
@@ -25,14 +23,74 @@ import com.google.api.client.util.store.FileDataStoreFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
//todo add docs
|
||||
/**
|
||||
* Classe piu' importante per la connessione al fitbit
|
||||
*/
|
||||
public class AuthFitbit {
|
||||
|
||||
/**
|
||||
* Un logger per rendere le cose semplici in caso di casini
|
||||
*/
|
||||
private static final Logger LOG = LoggerFactory.getLogger("Fitbit Response");
|
||||
|
||||
/**
|
||||
* Un mapper per trasformare i json in mappe.
|
||||
*/
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
|
||||
/**
|
||||
* Directory dove vengono messi i dati utente (Token)<br>
|
||||
* <br>
|
||||
* Throw a Warning when change permission: they said it's a google bug 'cause is meant to run in linux/unix<br>
|
||||
* https://stackoverflow.com/questions/30634827/warning-unable-to-change-permissions-for-everybody<br>
|
||||
* https://github.com/google/google-http-java-client/issues/315<br>
|
||||
*/
|
||||
private static final java.io.File DATA_STORE_DIR = new java.io.File(System.getProperty("user.home"), ".store/seniorAssistant");
|
||||
|
||||
/**
|
||||
* OAuth 2 scope.<br>
|
||||
* Nel nostro caso sono le varie categorie dove si trovano le informazioni di cui abbiamo bisogno
|
||||
*/
|
||||
private static final String SCOPE[] = new String[]{"activity","heartrate","sleep","settings"};
|
||||
|
||||
/**
|
||||
* Instanza globale di HttpTranspot necessaria per l'autorizzazione e per le richieste
|
||||
*/
|
||||
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
|
||||
|
||||
/**
|
||||
* Istanza globale di una Json Factory
|
||||
*/
|
||||
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
|
||||
|
||||
/**
|
||||
* Url dove e' possiblie richiedere il token
|
||||
*/
|
||||
private static final String TOKEN_SERVER_URL = " https://api.fitbit.com/oauth2/token";
|
||||
|
||||
/**
|
||||
* Pagina dove si richiede l'autorizzazione a tutti i campi richiesti
|
||||
*/
|
||||
private static final String AUTHORIZATION_SERVER_URL = "https://www.fitbit.com/oauth2/authorize";
|
||||
|
||||
/**
|
||||
* Istanza globale del {@link DataStoreFactory}. Il miglior metodo e' creare una singola
|
||||
* istanza globale condivisa attraverso tutta l'applicazione.
|
||||
*/
|
||||
private static FileDataStoreFactory DATA_STORE_FACTORY;
|
||||
|
||||
/**
|
||||
* Un HttpRequestFactory che serve per creare una richiesta http
|
||||
*/
|
||||
private final HttpRequestFactory requestFactory;
|
||||
|
||||
/**
|
||||
* Prova a connettersi al sito di Fitbit per controllare l'autorizzazione<br>
|
||||
* Se la richiesta inviata e' sbagliata lancia una eccezione.<br>
|
||||
* Se l'utente non ha ancora autorizzato l'applicazioe, allora una pagina sul browser (o un link in console) appare<br>
|
||||
* ci si logga e si lascia l'autorizzazione a questa applicazione.
|
||||
* @throws Exception per qualunque cosa apparentemente (e noi ci siamo riusciti)
|
||||
*/
|
||||
public AuthFitbit() throws Exception {
|
||||
DATA_STORE_FACTORY = new FileDataStoreFactory(DATA_STORE_DIR);
|
||||
final Credential credential = authorize();
|
||||
@@ -43,34 +101,9 @@ public class AuthFitbit {
|
||||
});
|
||||
}
|
||||
|
||||
private static ObjectMapper mapper = new ObjectMapper();
|
||||
/** Directory to store user credentials. */
|
||||
/* Throw a Warning when change permission: they said it's a google bug 'cause is meant to run in linux/unix
|
||||
*
|
||||
* https://stackoverflow.com/questions/30634827/warning-unable-to-change-permissions-for-everybody
|
||||
* https://github.com/google/google-http-java-client/issues/315
|
||||
*/
|
||||
private static final java.io.File DATA_STORE_DIR =
|
||||
new java.io.File(System.getProperty("user.home"), ".store/seniorAssistant");
|
||||
|
||||
/**
|
||||
* Global instance of the {@link DataStoreFactory}. The best practice is to make it a single
|
||||
* globally shared instance across your application.
|
||||
* Autorizza l'applicazione ad accedere ai dati utente richiesti
|
||||
*/
|
||||
private static FileDataStoreFactory DATA_STORE_FACTORY;
|
||||
|
||||
/** OAuth 2 scope. */
|
||||
private static final String SCOPE[] = new String[]{"activity","heartrate","sleep","settings"};
|
||||
/** Global instance of the HTTP transport. */
|
||||
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
|
||||
|
||||
/** Global instance of the JSON factory. */
|
||||
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
|
||||
|
||||
private static final String TOKEN_SERVER_URL = " https://api.fitbit.com/oauth2/token";
|
||||
private static final String AUTHORIZATION_SERVER_URL = "https://www.fitbit.com/oauth2/authorize";
|
||||
|
||||
/** Authorizes the installed application to access user's protected data. */
|
||||
private Credential authorize() throws Exception {
|
||||
// set up authorization code flow
|
||||
AuthorizationCodeFlow flow = new AuthorizationCodeFlow.Builder(BearerToken
|
||||
@@ -90,38 +123,39 @@ public class AuthFitbit {
|
||||
return new AuthorizationCodeInstalledApp(flow, receiver).authorize( "user" );
|
||||
}
|
||||
|
||||
public <O> O run(String url, Class<O> returnClass) throws IOException {
|
||||
return run(url, returnClass, false);
|
||||
}
|
||||
|
||||
public <O> O run(String url, Class<O> returnClass, boolean useAsParse) throws IOException {
|
||||
FITBITUrl fitbitUrl = new FITBITUrl(url);
|
||||
fitbitUrl.setFields("");
|
||||
|
||||
HttpRequest request = requestFactory.buildGetRequest(fitbitUrl);
|
||||
/**
|
||||
* Effettua una chiamata al server fitbit richiedendo i dati indicati dall'url
|
||||
*
|
||||
* @param url l'url in cui effettuare la richiesta
|
||||
* @return una stringa in formato Json, che e' il risultato
|
||||
* @throws IOException nel caso ci sia un errore con la richiesta
|
||||
*/
|
||||
public String run(String url) throws IOException {
|
||||
GenericUrl genericUrl = new GenericUrl(url);
|
||||
HttpRequest request = requestFactory.buildGetRequest(genericUrl);
|
||||
HttpResponse response = request.execute();
|
||||
|
||||
/*
|
||||
GenericJson json = response.parseAs(GenericJson.class);
|
||||
String content = response.parseAsString();
|
||||
response.disconnect();
|
||||
LOG.debug("Recived: " + content);
|
||||
|
||||
System.out.println(returnClass.getSimpleName());
|
||||
System.out.println(url);
|
||||
System.out.println(json.toPrettyString());
|
||||
return content;
|
||||
}
|
||||
|
||||
return mapper.readValue(json.toString(), returnClass);
|
||||
*/
|
||||
|
||||
/**/
|
||||
O ret = ( useAsParse ?
|
||||
response.parseAs(returnClass) :
|
||||
mapper.readValue(response.parseAs(GenericJson.class).toString(), returnClass)
|
||||
);
|
||||
|
||||
response.disconnect();
|
||||
|
||||
// todo remove this, it's only useful if you need to see the request
|
||||
LOG.info(GsonFactory.getDefaultFactory().getGson().toJson(ret));
|
||||
/**
|
||||
* Fa una chiamata al server fitbit richiedendo i dati indicati dall'url<br>
|
||||
* La classe e' richiesta se si vuole fare il parsing diretto e ricevere la classe parsificata con un mapper<br>
|
||||
* in questo modo non tutti i campi devono esistere
|
||||
*
|
||||
* @param url l'url in cui effettuare la richiesta
|
||||
* @param returnClass la classe da ritornare
|
||||
* @param <O> la classe che ritorna
|
||||
* @return un oggetto rappresentante la richiesta fatta all'url
|
||||
* @throws IOException nel caso ci sia un errore con la richiesta o con il parsing di quest'ultima
|
||||
*/
|
||||
public <O> O run(String url, Class<O> returnClass) throws IOException {
|
||||
O ret = MAPPER.readValue(this.run(url), returnClass);
|
||||
LOG.debug("Saved in class: " + JSON_FACTORY.toString(ret));
|
||||
|
||||
return ret;
|
||||
/**/
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
package oauth;
|
||||
|
||||
import com.google.api.client.http.GenericUrl;
|
||||
import com.google.api.client.util.Key;
|
||||
|
||||
// todo add docs
|
||||
public class FITBITUrl extends GenericUrl {
|
||||
|
||||
@Key
|
||||
private String fields;
|
||||
|
||||
public FITBITUrl(String encodedUrl) {
|
||||
super(encodedUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the fields
|
||||
*/
|
||||
public String getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fields the fields to set
|
||||
*/
|
||||
public void setFields(String fields) {
|
||||
this.fields = fields;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,28 @@
|
||||
package oauth;
|
||||
|
||||
// todo add docs
|
||||
/**
|
||||
* Classe supporto per l'oauth contenente tutti i dati dell'applicazione
|
||||
*/
|
||||
public class OAuth2ClientCredentials {
|
||||
|
||||
/** Value of the "API Key". */
|
||||
/**
|
||||
* Il valore dell' "API Key".
|
||||
*/
|
||||
public static final String API_KEY = "22CSTL"; //maybe togliere le virgolette
|
||||
|
||||
/** Value of the "API Secret". */
|
||||
/**
|
||||
* Il valore dell' "API Secret"
|
||||
*/
|
||||
public static final String API_SECRET = "ea2452013abd35609940ce5601960a08"; //maybe togliere le virgolette
|
||||
|
||||
/** Port in the "Callback URL". */
|
||||
/**
|
||||
* La porta per il "Callback URL".
|
||||
*/
|
||||
public static final int PORT = 8080;
|
||||
|
||||
/** Domain name in the "Callback URL". */
|
||||
/**
|
||||
* Il dominio del "Callback URL"
|
||||
*/
|
||||
public static final String DOMAIN = "127.0.0.1";
|
||||
}
|
||||
|
||||
|
||||
@@ -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