Some changes
- Database now has insert in background (not tested tho) - Hue lights tested on simulator - LocalServerReciver.java is now part of package, but still throw exception (maybe is not only this class) - Sleep class have changed (not tested) - Fitbit now thread safe (maybe?) - build.gradle cleaned * for all the classes not tested is because i need the account fitbit, and TROPPO SBATTI for ask
This commit is contained in:
16
build.gradle
16
build.gradle
@@ -16,14 +16,9 @@ repositories {
|
||||
dependencies {
|
||||
// Tests
|
||||
testCompile group: 'junit', name: 'junit', version: '4.12'
|
||||
// implementation 'junit:junit:4.12'
|
||||
|
||||
// GSON but works even without it anyway
|
||||
// compile "com.google.code.gson:gson:2.8.4"
|
||||
|
||||
// Database
|
||||
compile "org.xerial:sqlite-jdbc:3.21.0.1"
|
||||
// compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.12'
|
||||
|
||||
// Rest request
|
||||
compile 'org.apache.httpcomponents:httpclient:4.5.6'
|
||||
@@ -36,26 +31,19 @@ dependencies {
|
||||
|
||||
// Server Spark
|
||||
compile "com.sparkjava:spark-core:2.7.2"
|
||||
// compile 'org.apache.commons:commons-lang3:3.4'
|
||||
// compile group: 'org.eclipse.jetty', name: 'jetty-webapp', version: '9.4.11.v20180605'
|
||||
// compile 'org.eclipse.jetty:jetty-client:9.4.11.v20180605'
|
||||
// compile 'org.eclipse.jetty.websocket:websocket-server:9.4.11.v20180605'
|
||||
|
||||
// Oauth
|
||||
// compile group: 'org.pac4j', name: 'spark-pac4j', version: '2.3.0' //todo use this insted?
|
||||
compile ( group: 'com.google.oauth-client', name: 'google-oauth-client-jetty', version: '1.23.0') {
|
||||
// don't pull in an old ancient jetty version
|
||||
// todo it doesn't seems to work
|
||||
exclude group: 'org.mortbay.jetty', module: 'jetty'
|
||||
exclude group: 'org.mortbay.jetty', module: 'jetty-util'
|
||||
exclude group: 'org.mortbay.jetty', module: 'servlet-api'
|
||||
}
|
||||
// compile group: 'org.mortbay.jetty', name: 'jetty', version: '7.0.0.pre5'
|
||||
// compile group: 'org.mortbay.jetty', name: 'servlet-api', version: '3.0.20100224'
|
||||
compile 'com.google.api-client:google-api-client:1.23.0'
|
||||
|
||||
// DialogFlow
|
||||
compile "ai.api:libai:1.6.12"
|
||||
// compile 'com.google.cloud:google-cloud-dialogflow:0.59.0-alpha' // for the v2 of dialogflow
|
||||
compile group: "ai.api", name:"libai", version:"1.6.12"
|
||||
|
||||
// objectMapper for fitbitdata
|
||||
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.5' // maybe duplicate in google-api
|
||||
|
||||
@@ -4,6 +4,7 @@ import ai.api.GsonFactory;
|
||||
import ai.api.model.AIResponse;
|
||||
import ai.api.model.Fulfillment;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -78,7 +79,7 @@ public class DialogFlowWebHook {
|
||||
try {
|
||||
log.info("AZIONE: "+input.getResult().getAction());
|
||||
Action action = actions.get(input.getResult().getAction());
|
||||
text = action.doAction();
|
||||
text = action.doAction(input.getResult().getParameters());
|
||||
} catch (NullPointerException e) {
|
||||
log.info("NESSUNA AZIONE TROVATA");
|
||||
text = ERROR;
|
||||
@@ -102,8 +103,10 @@ 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
|
||||
* @return Una stringa che verra' usata come messaggio o null se non si vuole
|
||||
*/
|
||||
String doAction();
|
||||
String doAction(Map<String, JsonElement> params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ 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;
|
||||
@@ -74,9 +75,8 @@ public class Fitbit {
|
||||
* @return un intero rappresentante i passi effettuati
|
||||
* @throws IOException nel caso la richiesta non vada a buon fine
|
||||
*/
|
||||
public int getSteps() throws IOException {
|
||||
if (shouldUpdateFor(Steps.class))
|
||||
steps = auth.run(BASIC_URL + "1" + USER + "activities/steps/date/today/1w.json", Steps.class);
|
||||
public synchronized int getSteps() throws IOException {
|
||||
steps = update(Steps.class, steps, "1" + USER + "activities/steps/date/today/1w.json");
|
||||
return steps.getSteps();
|
||||
}
|
||||
|
||||
@@ -87,9 +87,10 @@ 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 double getHeartRate() throws IOException {
|
||||
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
|
||||
@@ -98,22 +99,19 @@ public class Fitbit {
|
||||
* @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 double getHeartRate(int lastMinutes) throws IOException {
|
||||
public synchronized double getHeartRate(int lastMinutes) throws IOException {
|
||||
if(lastMinutes<=0)
|
||||
return -1;
|
||||
if (shouldUpdateFor(HeartRate.class)) {
|
||||
long currentMillisec = System.currentTimeMillis();
|
||||
|
||||
String now = getHourMinutes(currentMillisec);
|
||||
String ago = getHourMinutes(currentMillisec - (MINUTE * lastMinutes));
|
||||
long currentMillisec = System.currentTimeMillis();
|
||||
|
||||
if (now.compareTo(ago) < 0)
|
||||
ago = "00:00";
|
||||
String now = getHourMinutes(currentMillisec);
|
||||
String ago = getHourMinutes(currentMillisec - (MINUTE * lastMinutes));
|
||||
|
||||
heart = auth.run(
|
||||
BASIC_URL + "1" + USER + "activities/heart/date/today/1d/1sec/time/" + ago + "/" + now + ".json",
|
||||
HeartRate.class);
|
||||
}
|
||||
if (now.compareTo(ago) < 0)
|
||||
ago = "00:00";
|
||||
|
||||
heart = update(HeartRate.class, heart,"1" + USER + "activities/heart/date/today/1d/1sec/time/" + ago + "/" + now + ".json");
|
||||
return heart.getAverage();
|
||||
}
|
||||
|
||||
@@ -123,33 +121,48 @@ public class Fitbit {
|
||||
* @return un intero rappresentante le ore passate a dormire
|
||||
* @throws IOException nel caso la richiesta non vada a buon fine
|
||||
*/
|
||||
public Object getHoursSleep() throws IOException {
|
||||
if (shouldUpdateFor(Sleep.class))
|
||||
sleep = auth.run(BASIC_URL + "1.2" + USER + "sleep/date/today.json", Sleep.class);
|
||||
return sleep.getMinutesAsleep();
|
||||
public synchronized long getHoursSleep() throws IOException {
|
||||
sleep = update(Sleep.class, sleep,"1.2" + USER + "sleep/date/today.json");
|
||||
return sleep.getMinutesAsleep()/60;
|
||||
}
|
||||
|
||||
/**
|
||||
* Semplice classe che controlla che si possa fare l'update o meno di una specifica classe<br>
|
||||
* Se e' possibile fare l'update inserisce la classe nella mappa<br>
|
||||
* In questo modo se questa funzione viene chiamata una seconda volta con lo stesso parametro restituira' falso<br>
|
||||
* a meno che non si aspetti 5 minuti
|
||||
*
|
||||
* @param type la classe da fare l'update
|
||||
* @return vero se si puo' fare l'update
|
||||
* Ricevi tutti i dati presenti per il sonno di questo giorno.
|
||||
* La lista contiene per ogni volta che l'utente ha dormito:<br>
|
||||
* - la data di quando si e' addormentato<br>
|
||||
* - la durata del sonno<br>
|
||||
* - la data di fine<br>
|
||||
* @return una lista contenente ogni volta che l'utente ha dormito
|
||||
* @throws IOException
|
||||
*/
|
||||
private boolean shouldUpdateFor(Class<?> type) {
|
||||
public synchronized List<Sleep.SleepData> getDetailedSleep() throws IOException {
|
||||
sleep = update(Sleep.class, sleep,"1.2" + USER + "sleep/date/today.json");
|
||||
return sleep.getDatas();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* @param varClass la classe della variabile passata
|
||||
* @param variable la variabile che vede fare l'update
|
||||
* @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 {
|
||||
try {
|
||||
long current = System.currentTimeMillis();
|
||||
long latest = latestRequest.get(type);
|
||||
long latest = latestRequest.get(varClass);
|
||||
|
||||
// don't update
|
||||
if(current - latest < MINUTE * 5)
|
||||
return false;
|
||||
return variable;
|
||||
} catch (NullPointerException e) {
|
||||
// do nothing and update
|
||||
}
|
||||
|
||||
latestRequest.put(heart.getClass(), System.currentTimeMillis());
|
||||
return true;
|
||||
latestRequest.put(varClass, System.currentTimeMillis());
|
||||
return auth.run(BASIC_URL + url, varClass);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package device;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import ai.api.GsonFactory;
|
||||
import support.Rest;
|
||||
|
||||
/**
|
||||
@@ -13,7 +15,27 @@ public class Hue {
|
||||
/**
|
||||
* La luminopsita' massima a cui si puo' arrivare
|
||||
*/
|
||||
public static final int MAX_BRIGHTNESS = 255;
|
||||
public static final int MAX_BRIGHTNESS = 254;
|
||||
|
||||
/**
|
||||
* Una mappa che ad ogni colore (in lingua ita) assegna il proprio valore in 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";
|
||||
/**
|
||||
@@ -38,14 +60,13 @@ public class Hue {
|
||||
this("172.30.1.138", "C0vPwqjJZo5Jt9Oe5HgO6sBFFMxgoR532IxFoGmx");
|
||||
}
|
||||
|
||||
//todo maybe the key is the user, but who knows?
|
||||
/**
|
||||
* Cerca le luci Philips Hue nell'indirizzo specificato e con la chiave specificata
|
||||
* Cerca le luci Philips Hue nell'indirizzo specificato e con l'utente specificato
|
||||
* @param ip l'indirizzo IP
|
||||
* @param key la chiuave utililzzata
|
||||
* @param user l'utente
|
||||
*/
|
||||
public Hue(String ip, String key) {
|
||||
this("http://" + ip + "/api/" + key + "/lights/");
|
||||
public Hue(String ip, String user) {
|
||||
this("http://" + ip + "/api/" + user + "/lights/");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,7 +82,7 @@ public class Hue {
|
||||
|
||||
/**
|
||||
* Ritorna un insieme contenente tutti i nomi delle luci che si sono trovate
|
||||
*
|
||||
*
|
||||
* @return l'insieme dei nomi delle luci
|
||||
*/
|
||||
public Set<String> getNameLights() {
|
||||
@@ -82,22 +103,14 @@ public class Hue {
|
||||
* Accende tutte le luci controllate
|
||||
*/
|
||||
public void turnOn() {
|
||||
for (String light : allLights.keySet()) {
|
||||
String callURL = lightsURL + light + "/state";
|
||||
String body = "{ \"on\" : true }";
|
||||
Rest.put(callURL, body, "application/json");
|
||||
}
|
||||
setState("on", "true");
|
||||
}
|
||||
|
||||
/**
|
||||
* Spegne tutte le luci controllate
|
||||
*/
|
||||
public void turnOff() {
|
||||
for (String light : allLights.keySet()) {
|
||||
String callURL = lightsURL + light + "/state";
|
||||
String body = "{ \"on\" : false }";
|
||||
Rest.put(callURL, body, "application/json");
|
||||
}
|
||||
setState("on", "false");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -115,11 +128,7 @@ public class Hue {
|
||||
public void setBrightness(int num) {
|
||||
if (num<0)
|
||||
num=0;
|
||||
for (String light : allLights.keySet()) {
|
||||
String callURL = lightsURL + light + "/state";
|
||||
String body = "{ \"bri\" : "+num+" }";
|
||||
Rest.put(callURL, body, "application/json");
|
||||
}
|
||||
setState("bri", String.valueOf(num));
|
||||
brightness = num;
|
||||
}
|
||||
|
||||
@@ -161,25 +170,27 @@ public class Hue {
|
||||
decreaseBrightness(10);
|
||||
}
|
||||
|
||||
public void changeColor(String colorName) {
|
||||
String hueColor = GsonFactory.getDefaultFactory().getGson().toJson(COLORS.get(colorName));
|
||||
setState("xy", hueColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifica il colore delle luci in modo da fare un bel effetto arcobaleno continuo
|
||||
*/
|
||||
public void colorLoop() {
|
||||
for (String light : allLights.keySet()) {
|
||||
String callURL = lightsURL + light + "/state";
|
||||
String body = "{ \"on\" : true, \"effect\" : \"colorloop\" }";
|
||||
Rest.put(callURL, body, "application/json");
|
||||
}
|
||||
setState("effect", "colorloop");
|
||||
}
|
||||
|
||||
/**
|
||||
* Funzione generale per poter utilizzare qualunque valore, ma non funziona
|
||||
* Funzione generale per poter utilizzare qualunque valore, ma non funziona<br>
|
||||
* Da testare, visto che mi sembra strano che non funzi...
|
||||
* e invece funziona.
|
||||
*/
|
||||
/*public void setAttribute(String attribute, String value){
|
||||
for (String light : allLights.keySet()) {
|
||||
String callURL = lightsURL + light + "/state";
|
||||
String body = "{ \""+attribute+"\" : "+value+" }";
|
||||
Rest.put(callURL, body, "application/json");
|
||||
}
|
||||
}*/
|
||||
public void setState(String attribute, String value){
|
||||
for (String light : allLights.keySet())
|
||||
Rest.put(lightsURL + light + "/state",
|
||||
"{ \"" + attribute + "\" : " + value + " }",
|
||||
"application/json");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,11 @@ package device.fitbitdata;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@@ -10,12 +15,47 @@ public class Sleep {
|
||||
|
||||
private int minutesAsleep;
|
||||
|
||||
private List<SleepData> datas;
|
||||
|
||||
public int getMinutesAsleep() {
|
||||
return minutesAsleep;
|
||||
}
|
||||
|
||||
public List<SleepData> getDatas() {
|
||||
return datas;
|
||||
}
|
||||
|
||||
@JsonProperty("summary")
|
||||
public void setMinutesAsleep(Map<String, Object> map) {
|
||||
minutesAsleep = (int) map.get("totalMinutesAsleep");
|
||||
}
|
||||
|
||||
@JsonProperty("sleep")
|
||||
public void setSleepsList(Map<String, Object>[] array) {
|
||||
datas = new ArrayList<>();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat();
|
||||
for(Map<String, Object> map : array) {
|
||||
Date date_start = null;
|
||||
try {
|
||||
date_start = sdf.parse((String) map.get("startTime"));
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
int duration = (int) map.get("duration");
|
||||
|
||||
datas.add(new SleepData(date_start, duration));
|
||||
}
|
||||
}
|
||||
|
||||
public class SleepData {
|
||||
public final Date start_date;
|
||||
public final long duration;
|
||||
public final Date end_date;
|
||||
|
||||
public SleepData(Date start_date, long duration) {
|
||||
this.start_date = start_date;
|
||||
this.duration = duration;
|
||||
this.end_date = start_date!=null? new Date(start_date.getTime() + duration):null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
package main;
|
||||
|
||||
import ai.api.GsonFactory;
|
||||
import device.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import support.DBConnect;
|
||||
import support.Database;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
// todo docs
|
||||
/**
|
||||
* Created by 20015159 on 28/08/2018.
|
||||
*/
|
||||
@@ -13,66 +17,76 @@ public class Main {
|
||||
/**
|
||||
* Un Logger per capire meglio quali pezzi vengono eseguiti e quali no.
|
||||
*/
|
||||
private static Logger log = LoggerFactory.getLogger("SeniorAssistant");
|
||||
private static final Logger LOG = LoggerFactory.getLogger("SeniorAssistant");
|
||||
|
||||
private static Hue lights;
|
||||
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) {
|
||||
log.info("Connecting to hue lights");
|
||||
Hue lights = new Hue();
|
||||
log.info("Connecting to the sensors");
|
||||
Sensor sensor = new Sensor();
|
||||
LOG.info("Connecting to hue lights");
|
||||
lights = new Hue("localhost:8090", "newdeveloper");
|
||||
|
||||
LOG.info("Connecting to the sensors");
|
||||
sensor = new Sensor();
|
||||
|
||||
try {
|
||||
log.info("Connecting to Fitbit");
|
||||
Fitbit fitbit = new Fitbit();
|
||||
startInsertData(fitbit); // add here functions associated with fitbit
|
||||
} catch (Exception e) { // in this way the program will continue without fitbit
|
||||
LOG.info("Connecting to Database");
|
||||
database = Database.getInstance();
|
||||
|
||||
LOG.info("Connecting to Fitbit");
|
||||
fitbit = new Fitbit();
|
||||
|
||||
startInsertData();
|
||||
// add here functions associated with fitbit
|
||||
} catch (Exception e) { // in this way the program will continue even without fitbit
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
startWebhook(lights);
|
||||
startWebhook();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fa partire il server Webhook per DialogFlow e continua l'esecuzione
|
||||
* @param hue Le luci che vengono modificate a seconda delle richieste dell'utente
|
||||
*/
|
||||
private static void startWebhook(Hue hue) {
|
||||
log.info("Adding actions to Webhook");
|
||||
private static void startWebhook() {
|
||||
LOG.info("Adding actions to Webhook");
|
||||
DialogFlowWebHook df = new DialogFlowWebHook();
|
||||
|
||||
df.addOnAction("LightsON", () -> {hue.turnOn(); return "Luci accese";});
|
||||
df.addOnAction("LightsOFF", () -> {hue.turnOff(); return "Luci spente";});
|
||||
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;});
|
||||
|
||||
log.info("Starting Webhook");
|
||||
LOG.info("Starting Webhook");
|
||||
df.startServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cose da fare in questa funzione:
|
||||
* - far partire il database
|
||||
* - ogni ora aggiornare i dati del cuore. (Runnable che gira da se')
|
||||
* - alla fine della giornata fare un riepilogo del paziente (Runnable che gira da se')
|
||||
* (magari ci si calcola quando bisogna risvegliarsi e si mette un wait)
|
||||
* @param fibit da dove prende i dati
|
||||
* Gestione DB in modo che si aggiorni ogni ora
|
||||
*/
|
||||
private static void startInsertData(Fitbit fibit) {
|
||||
log.info("Connecting to DB to write fitbit data periodically");
|
||||
/*
|
||||
private static void startInsertData() {
|
||||
LOG.info("Connecting to DB to write fitbit data periodically");
|
||||
try {
|
||||
Connection conn = DBConnect.getInstance().getConnection();
|
||||
PreparedStatement st = conn.prepareStatement("");
|
||||
fitbit.getHoursSleep();
|
||||
|
||||
ResultSet rs = st.executeQuery();
|
||||
conn.close();
|
||||
Database database = Database.getInstance();
|
||||
|
||||
} catch (SQLException e) {
|
||||
Thread hourlyData = new Thread(database.insertHourlyData(fitbit), "updating-hour-data");
|
||||
Thread dailyData = new Thread(database.insertDailyData(fitbit), "updating-day-data");
|
||||
|
||||
hourlyData.start();
|
||||
dailyData.start();
|
||||
LOG.info("Threads started for updating database");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -86,7 +100,7 @@ public class Main {
|
||||
int brightness = sensor.getBrightnessLevel();
|
||||
|
||||
// AUTOMATIC
|
||||
// Gestione DB in modo che si aggiorni ogni ora
|
||||
/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
|
||||
@@ -94,7 +108,7 @@ public class Main {
|
||||
|
||||
// USER-INTERACTION
|
||||
// Dati del sonno/battito/passi che l'utente puo' richiedere
|
||||
// Gestione luci secondo le esigenze dell'utente
|
||||
/X/ Gestione luci secondo le esigenze dell'utente ( settare Dialogflow e server + risolvere bug )
|
||||
// EXTRA Gestione musica tramite comando vocale
|
||||
|
||||
// Randomly at night heavy metal start
|
||||
|
||||
@@ -3,12 +3,12 @@ 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;
|
||||
import com.google.api.client.auth.oauth2.Credential;
|
||||
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
|
||||
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
|
||||
import com.google.api.client.http.BasicAuthentication;
|
||||
import com.google.api.client.http.GenericUrl;
|
||||
import com.google.api.client.http.HttpRequest;
|
||||
@@ -22,10 +22,15 @@ import com.google.api.client.json.JsonObjectParser;
|
||||
import com.google.api.client.json.jackson2.JacksonFactory;
|
||||
import com.google.api.client.util.store.DataStoreFactory;
|
||||
import com.google.api.client.util.store.FileDataStoreFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
//todo add docs
|
||||
public class AuthFitbit {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger("Fitbit Response");
|
||||
|
||||
private final HttpRequestFactory requestFactory;
|
||||
|
||||
public AuthFitbit() throws Exception {
|
||||
@@ -114,6 +119,10 @@ public class AuthFitbit {
|
||||
);
|
||||
|
||||
response.disconnect();
|
||||
|
||||
// todo remove this, it's only useful if you need to see the request
|
||||
LOG.info(GsonFactory.getDefaultFactory().getGson().toJson(ret));
|
||||
|
||||
return ret;
|
||||
/**/
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ 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
|
||||
|
||||
298
src/main/java/oauth/LocalServerReceiver.java
Normal file
298
src/main/java/oauth/LocalServerReceiver.java
Normal file
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
// todo test if fitbit request still works with this class
|
||||
|
||||
package oauth;
|
||||
|
||||
import com.google.api.client.extensions.java6.auth.oauth2.VerificationCodeReceiver;
|
||||
import com.google.api.client.util.Throwables;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* OAuth 2.0 verification code receiver that runs a Jetty server on a free port, waiting for a
|
||||
* redirect with the verification code.
|
||||
*
|
||||
* <p>
|
||||
* Implementation is thread-safe.
|
||||
* </p>
|
||||
*
|
||||
* @since 1.11
|
||||
* @author Yaniv Inbar
|
||||
*/
|
||||
public final class LocalServerReceiver implements VerificationCodeReceiver {
|
||||
|
||||
private static final String LOCALHOST = "localhost";
|
||||
|
||||
private static final String CALLBACK_PATH = "/Callback";
|
||||
|
||||
/** Server or {@code null} before {@link #getRedirectUri()}. */
|
||||
private Server server;
|
||||
|
||||
/** Verification code or {@code null} for none. */
|
||||
String code;
|
||||
|
||||
/** Error code or {@code null} for none. */
|
||||
String error;
|
||||
|
||||
/** To block until receiving an authorization response or stop() is called. */
|
||||
final Semaphore waitUnlessSignaled = new Semaphore(0 /* initially zero permit */);
|
||||
|
||||
/** Port to use or {@code -1} to select an unused port in {@link #getRedirectUri()}. */
|
||||
private int port;
|
||||
|
||||
/** Host name to use. */
|
||||
private final String host;
|
||||
|
||||
/** Callback path of redirect_uri */
|
||||
private final String callbackPath;
|
||||
|
||||
/**
|
||||
* URL to an HTML page to be shown (via redirect) after successful login. If null, a canned
|
||||
* default landing page will be shown (via direct response).
|
||||
*/
|
||||
private String successLandingPageUrl;
|
||||
|
||||
/**
|
||||
* URL to an HTML page to be shown (via redirect) after failed login. If null, a canned
|
||||
* default landing page will be shown (via direct response).
|
||||
*/
|
||||
private String failureLandingPageUrl;
|
||||
|
||||
/**
|
||||
* Constructor that starts the server on {@link #LOCALHOST} and an unused port.
|
||||
*
|
||||
* <p>
|
||||
* Use {@link Builder} if you need to specify any of the optional parameters.
|
||||
* </p>
|
||||
*/
|
||||
public LocalServerReceiver() {
|
||||
this(LOCALHOST, -1, CALLBACK_PATH, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param host Host name to use
|
||||
* @param port Port to use or {@code -1} to select an unused port
|
||||
*/
|
||||
LocalServerReceiver(String host, int port,
|
||||
String successLandingPageUrl, String failureLandingPageUrl) {
|
||||
this(host, port, CALLBACK_PATH, successLandingPageUrl, failureLandingPageUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param host Host name to use
|
||||
* @param port Port to use or {@code -1} to select an unused port
|
||||
*/
|
||||
LocalServerReceiver(String host, int port, String callbackPath,
|
||||
String successLandingPageUrl, String failureLandingPageUrl) {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.callbackPath = callbackPath;
|
||||
this.successLandingPageUrl = successLandingPageUrl;
|
||||
this.failureLandingPageUrl = failureLandingPageUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRedirectUri() throws IOException {
|
||||
server = new Server(port != -1 ? port : 0);
|
||||
//Connector connector = server.getConnectors()[0];
|
||||
//connector.setHost(host);
|
||||
server.setHandler(new CallbackHandler());
|
||||
try {
|
||||
server.start();
|
||||
//port = connector.getLocalPort();
|
||||
} catch (Exception e) {
|
||||
Throwables.propagateIfPossible(e);
|
||||
throw new IOException(e);
|
||||
}
|
||||
return "http://" + host + ":" + port + callbackPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks until the server receives a login result, or the server is stopped
|
||||
* by {@link #stop()}, to return an authorization code.
|
||||
*
|
||||
* @return authorization code if login succeeds; may return {@code null} if the server
|
||||
* is stopped by {@link #stop()}
|
||||
* @throws IOException if the server receives an error code (through an HTTP request
|
||||
* parameter {@code error})
|
||||
*/
|
||||
@Override
|
||||
public String waitForCode() throws IOException {
|
||||
waitUnlessSignaled.acquireUninterruptibly();
|
||||
if (error != null) {
|
||||
throw new IOException("User authorization failed (" + error + ")");
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws IOException {
|
||||
waitUnlessSignaled.release();
|
||||
if (server != null) {
|
||||
try {
|
||||
server.stop();
|
||||
} catch (Exception e) {
|
||||
Throwables.propagateIfPossible(e);
|
||||
throw new IOException(e);
|
||||
}
|
||||
server = null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the host name to use. */
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the port to use or {@code -1} to select an unused port in {@link #getRedirectUri()}.
|
||||
*/
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns callback path used in redirect_uri.
|
||||
*/
|
||||
public String getCallbackPath() {
|
||||
return callbackPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder.
|
||||
*
|
||||
* <p>
|
||||
* Implementation is not thread-safe.
|
||||
* </p>
|
||||
*/
|
||||
public static final class Builder {
|
||||
|
||||
/** Host name to use. */
|
||||
private String host = LOCALHOST;
|
||||
|
||||
/** Port to use or {@code -1} to select an unused port. */
|
||||
private int port = -1;
|
||||
|
||||
private String successLandingPageUrl;
|
||||
private String failureLandingPageUrl;
|
||||
|
||||
private String callbackPath = CALLBACK_PATH;
|
||||
|
||||
/** Builds the {@link LocalServerReceiver}. */
|
||||
public LocalServerReceiver build() {
|
||||
return new LocalServerReceiver(host, port, callbackPath,
|
||||
successLandingPageUrl, failureLandingPageUrl);
|
||||
}
|
||||
|
||||
/** Returns the host name to use. */
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
/** Sets the host name to use. */
|
||||
public Builder setHost(String host) {
|
||||
this.host = host;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Returns the port to use or {@code -1} to select an unused port. */
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
/** Sets the port to use or {@code -1} to select an unused port. */
|
||||
public Builder setPort(int port) {
|
||||
this.port = port;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Returns the callback path of redirect_uri */
|
||||
public String getCallbackPath() {
|
||||
return callbackPath;
|
||||
}
|
||||
|
||||
/** Set the callback path of redirect_uri */
|
||||
public Builder setCallbackPath(String callbackPath) {
|
||||
this.callbackPath = callbackPath;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setLandingPages(String successLandingPageUrl, String failureLandingPageUrl) {
|
||||
this.successLandingPageUrl = successLandingPageUrl;
|
||||
this.failureLandingPageUrl = failureLandingPageUrl;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Jetty handler that takes the verifier token passed over from the OAuth provider and stashes it
|
||||
* where {@link #waitForCode} will find it.
|
||||
*/
|
||||
class CallbackHandler extends AbstractHandler {
|
||||
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
if (!CALLBACK_PATH.equals(target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
((Request) request).setHandled(true);
|
||||
error = request.getParameter("error");
|
||||
code = request.getParameter("code");
|
||||
|
||||
if (error == null && successLandingPageUrl != null) {
|
||||
response.sendRedirect(successLandingPageUrl);
|
||||
} else if (error != null && failureLandingPageUrl != null) {
|
||||
response.sendRedirect(failureLandingPageUrl);
|
||||
} else {
|
||||
writeLandingHtml(response);
|
||||
}
|
||||
response.flushBuffer();
|
||||
}
|
||||
finally {
|
||||
waitUnlessSignaled.release();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeLandingHtml(HttpServletResponse response) throws IOException {
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
response.setContentType("text/html");
|
||||
|
||||
PrintWriter doc = response.getWriter();
|
||||
doc.println("<html>");
|
||||
doc.println("<head><title>OAuth 2.0 Authentication Token Received</title></head>");
|
||||
doc.println("<body>");
|
||||
doc.println("Received verification code. You may now close this window.");
|
||||
doc.println("</body>");
|
||||
doc.println("</html>");
|
||||
doc.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package oauth;
|
||||
|
||||
// todo add docs
|
||||
public class OAuth2ClientCredentials {
|
||||
|
||||
/** Value of the "API Key". */
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
package support;
|
||||
|
||||
import java.sql.*;
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
public class DBConnect {
|
||||
|
||||
// todo add a db where we put daily (or hourly, but only for heart) updates
|
||||
public static final String DB_LOCATION = "jdbc:sqlite:src/main/resources/";
|
||||
public static final String DB_NAME = "user_data.db";
|
||||
|
||||
private static DBConnect instance;
|
||||
|
||||
private final Connection conn;
|
||||
|
||||
private DBConnect() throws SQLException {
|
||||
conn = DriverManager.getConnection(DB_LOCATION + DB_NAME);
|
||||
buildTablesIfNotExisting();
|
||||
}
|
||||
|
||||
public static DBConnect getInstance() {
|
||||
try {
|
||||
instance = instance==null? new DBConnect():instance;
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private void buildTablesIfNotExisting() throws SQLException {
|
||||
Statement statement = conn.createStatement();
|
||||
// todo working, but not quite well
|
||||
statement.execute("CREATE TABLE IF NOT EXISTS user (user VARCHAR(16) PRIMARY KEY, name VARCHAR(16), birthday DATE);");
|
||||
statement.execute("CREATE TABLE IF NOT EXISTS heart_rate (date DATE, rate DOUBLE, user VARCHAR(16), PRIMARY KEY(date, user));");
|
||||
}
|
||||
}
|
||||
150
src/main/java/support/Database.java
Normal file
150
src/main/java/support/Database.java
Normal file
@@ -0,0 +1,150 @@
|
||||
package support;
|
||||
|
||||
import device.Fitbit;
|
||||
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.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)
|
||||
*/
|
||||
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();
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Database.class);
|
||||
|
||||
private static Database instance;
|
||||
|
||||
private final Connection conn;
|
||||
|
||||
/**
|
||||
* Crea una connessione al Database specificato in DB_LOCATION e con il nome DB_NAME.
|
||||
* Se il Database non esiste lo crea e inizializza anche delle tabelle:
|
||||
* <ul>
|
||||
* <li>'total' contiene i dati utente giorno per giorno.</li>
|
||||
* <li>'heart' battito + orario</li>
|
||||
* <li>'sleep' inizio + fine + durata</li>
|
||||
* </ul>
|
||||
* @throws SQLException se qualcosa e' andato storto
|
||||
*/
|
||||
private Database() throws SQLException {
|
||||
CALENDAR.setTimeInMillis(System.currentTimeMillis());
|
||||
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 sleep (sleep_start DATE PRIMARY KEY, sleep_end DATE, duration INTEGER)");
|
||||
}
|
||||
|
||||
/**
|
||||
* Crea una connessione al Database specificato in DB_LOCATION e con il nome DB_NAME.
|
||||
* Se il Database non esiste lo crea e inizializza anche delle tabelle:
|
||||
* <ul>
|
||||
* <li>'total' contiene i dati utente giorno per giorno.</li>
|
||||
* <li>'heart' battito + orario</li>
|
||||
* <li>'sleep' inizio + fine + durata</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static Database getInstance() {
|
||||
try {
|
||||
instance = instance==null? new Database():instance;
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prendi il Runnable che automaticamente gestisce l'inserimento dei dati orari (per ora solo il battito cardiaco)
|
||||
* @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;
|
||||
|
||||
while(notInterrupted) {
|
||||
try {
|
||||
wait((retry? 1:59-CALENDAR.get(Calendar.MINUTE)) * 60000);
|
||||
if (retry == false) {
|
||||
heartRate = fitbit.getHeartRate(60);
|
||||
now = CALENDAR.getTime();
|
||||
}
|
||||
|
||||
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
|
||||
* @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;
|
||||
|
||||
while (notInterrupted) {
|
||||
int hourToWait = 23 - CALENDAR.get(Calendar.HOUR);
|
||||
|
||||
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) 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;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -10,8 +10,8 @@ public class TestDialogFlow {
|
||||
public void test01() {
|
||||
DialogFlowWebHook webHook = new DialogFlowWebHook();
|
||||
|
||||
webHook.addOnAction("LightsON", () -> {return "Luci accese";});
|
||||
webHook.addOnAction("LightsOFF", () -> {return "Luci spente";});
|
||||
webHook.addOnAction("LightsON", (param) -> {return "Luci accese";});
|
||||
webHook.addOnAction("LightsOFF", (param) -> {return "Luci spente";});
|
||||
|
||||
webHook.startServer();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package test;
|
||||
|
||||
import ai.api.GsonFactory;
|
||||
import device.Hue;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -8,38 +9,49 @@ import java.util.Set;
|
||||
|
||||
public class TestLights {
|
||||
|
||||
public static final int TIMEOUT = 200;
|
||||
|
||||
@Test
|
||||
synchronized public void firstTestLights() throws InterruptedException {
|
||||
Hue lights = new Hue();
|
||||
Hue lights = new Hue("localhost:8090", "newdeveloper");
|
||||
|
||||
Set<String> toRemove = new HashSet<>();
|
||||
for(String str: lights.getNameLights())
|
||||
if(!str.equals("4"))
|
||||
if(!(Integer.parseInt(str)%2 == 0))
|
||||
toRemove.add(str);
|
||||
lights.removeLights(toRemove);
|
||||
|
||||
for(int i=0; i<10; i++) {
|
||||
lights.turnOn();
|
||||
this.wait(0b11001000); // 200
|
||||
this.wait(TIMEOUT);
|
||||
lights.turnOff();
|
||||
this.wait(0b11001000); // 200
|
||||
this.wait(TIMEOUT);
|
||||
}
|
||||
|
||||
lights.turnOn();
|
||||
for(int i=256; i>=0; i--) {
|
||||
for(int i=Hue.MAX_BRIGHTNESS; i>0; i-=10) {
|
||||
lights.setBrightness(i);
|
||||
this.wait(25);
|
||||
this.wait(TIMEOUT);
|
||||
}
|
||||
|
||||
for(int i=0; i<256; i++) {
|
||||
for(int i=0; i<Hue.MAX_BRIGHTNESS; i+=10) {
|
||||
lights.setBrightness(i);
|
||||
this.wait(25);
|
||||
this.wait(TIMEOUT);
|
||||
}
|
||||
|
||||
lights.setBrightness(Hue.MAX_BRIGHTNESS);
|
||||
lights.colorLoop(); // todo not working in simulator
|
||||
this.wait(TIMEOUT*10);
|
||||
|
||||
// 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}));
|
||||
this.wait(TIMEOUT);
|
||||
}
|
||||
|
||||
lights.setBrightness(150);
|
||||
lights.colorLoop();
|
||||
this.wait(20000); // 10 sec
|
||||
lights.turnOff();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user