diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..c8d40b5
--- /dev/null
+++ b/META-INF/MANIFEST.MF
@@ -0,0 +1,19 @@
+Manifest-Version: 1.0
+Class-Path: jackson-annotations-2.9.0.jar jetty-server-9.4.8.v20171121
+ .jar google-oauth-client-jetty-1.23.0.jar httpcore-4.4.10.jar google-
+ http-client-1.23.0.jar jetty-xml-9.4.8.v20171121.jar jetty-client-9.4
+ .8.v20171121.jar commons-logging-1.2.jar jetty-util-9.4.8.v20171121.j
+ ar google-http-client-jackson2-1.23.0.jar google-oauth-client-java6-1
+ .23.0.jar jackson-databind-2.9.5.jar zway-lib-0.2.9-SNAPSHOT.jar jett
+ y-security-9.4.8.v20171121.jar guava-jdk5-17.0.jar gson-2.8.1.jar slf
+ 4j-simple-1.7.25.jar javax.servlet-api-3.1.0.jar jetty-webapp-9.4.8.v
+ 20171121.jar jsr305-1.3.9.jar jetty-io-9.4.8.v20171121.jar websocket-
+ client-9.4.8.v20171121.jar sqlite-jdbc-3.21.0.1.jar websocket-api-9.4
+ .8.v20171121.jar spark-core-2.7.2.jar httpclient-4.5.6.jar libai-1.6.
+ 12.jar google-oauth-client-1.23.0.jar websocket-server-9.4.8.v2017112
+ 1.jar jetty-servlet-9.4.8.v20171121.jar google-api-client-1.23.0.jar
+ jetty-http-9.4.8.v20171121.jar websocket-common-9.4.8.v20171121.jar w
+ ebsocket-servlet-9.4.8.v20171121.jar commons-codec-1.10.jar jackson-c
+ ore-2.9.5.jar slf4j-api-1.7.25.jar
+Main-Class: main.Main
+
diff --git a/src/main/java/device/Fitbit.java b/src/main/java/device/Fitbit.java
index 6bde0e6..8a67048 100644
--- a/src/main/java/device/Fitbit.java
+++ b/src/main/java/device/Fitbit.java
@@ -119,7 +119,7 @@ public class Fitbit {
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");
+ heart = update(HeartRate.class, null,"1" + USER + "activities/heart/date/today/1d/1sec/time/" + ago + "/" + now + ".json");
return heart.getAverage();
}
@@ -154,7 +154,7 @@ public class Fitbit {
* Altrimenti viene ritornata la variabile passata
*
* @param varClass la classe della variabile passata
- * @param variable la variabile che vede fare l'update
+ * @param variable la variabile che deve fare l'update (passando null si forza la richiesta)
* @param url l'url da cui prende i dati aggiornati
* @return la variabile aggiornata
*/
@@ -164,7 +164,7 @@ public class Fitbit {
long latest = latestRequest.get(varClass);
// don't update
- if(current - latest < MINUTE * 5)
+ if( (variable!=null) && (current - latest < MINUTE * 5) )
return variable;
} catch (NullPointerException e) {
// do nothing and update
diff --git a/src/main/java/device/Hue.java b/src/main/java/device/Hue.java
index 647ec99..5e1148f 100644
--- a/src/main/java/device/Hue.java
+++ b/src/main/java/device/Hue.java
@@ -62,10 +62,9 @@ public class Hue {
/**
* Cerca le luci Philips Hue a ll'indirizzo http://172.30.1.138/api/C0vPwqjJZo5Jt9Oe5HgO6sBFFMxgoR532IxFoGmx/lights/
+ * @throws NullPointerException se non trova nessun bridge
*/
- public Hue () {
- this("172.30.1.138", "C0vPwqjJZo5Jt9Oe5HgO6sBFFMxgoR532IxFoGmx");
- }
+ public Hue () throws NullPointerException { this("172.30.1.138", "C0vPwqjJZo5Jt9Oe5HgO6sBFFMxgoR532IxFoGmx"); }
/**
* Cerca le luci Philips Hue nell'indirizzo specificato e con l'utente specificato.
@@ -73,11 +72,15 @@ public class Hue {
* (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
+ * @throws NullPointerException se non trova nessun bridge
*/
- public Hue(String ip, String user) {
+ public Hue(String ip, String user) throws NullPointerException {
lightsURL = "http://" + ip + "/api/" + user + "/lights/";
allLights = (Map>)Rest.get(lightsURL);
+ if(allLights.isEmpty())
+ throw new NullPointerException("Non e' stato possibile connettersi alle luci");
+
if(allLights.size() != 0) {
double bri = 0;
double hue = 0;
@@ -88,8 +91,11 @@ public class Hue {
}
bri = bri/allLights.size();
hue = hue/allLights.size();
- setState("bri", (int) bri );
- setState("hue", (int) hue );
+
+ Map map = new HashMap<>();
+ map.put("bri", (int)bri);
+ map.put("hue", (int)hue);
+ setState(map);
brightness = (bri*MAX_BRIGHTNESS)/100;
}
@@ -112,15 +118,21 @@ public class Hue {
allLights.remove(string);
}
+ /**
+ * Accende o spegne le luci controllate
+ * @param on vero se si vuole le luci accese, false per spegnerle
+ */
+ public void on(boolean on) { setState("on", on, false); }
+
/**
* Accende tutte le luci controllate
*/
- public void turnOn() { setState("on", true, false); }
+ public void turnOn() { on(true); }
/**
* Spegne tutte le luci controllate
*/
- public void turnOff() { setState("on", false, false); }
+ public void turnOff() { on(false); }
/**
* Ritorna la liminosita' attuale delle luci controllate
diff --git a/src/main/java/device/Sensor.java b/src/main/java/device/Sensor.java
index a2dc6af..c672b26 100644
--- a/src/main/java/device/Sensor.java
+++ b/src/main/java/device/Sensor.java
@@ -42,22 +42,25 @@ public class Sensor {
/**
* Crea un sensore contenente tutti i nodi
+ * @throws NullPointerException se non trova nessun sensore
*/
- public Sensor() {
- this(null);
- }
+ public Sensor() throws NullPointerException { this(null); }
/**
* Si connette ad un sensore che ha il nodeId selezioniato
* @param nodeId nodo che viene selezionato
+ * @throws NullPointerException se non trova nessun sensore
*/
- public Sensor (Integer nodeId) {
+ public Sensor (Integer nodeId) throws NullPointerException {
// create an instance of the Z-Way library; all the params are mandatory (we are not going to use the remote service/id)
IZWayApi zwayApi = new ZWayApiHttp(IP_ADDRESS, PORT, "http", USERNAME, PASSWORD, 0, false, new ZWaySimpleCallback());
// get all the Z-Wave devices
allZWaveDevices = zwayApi.getDevices();
+ if(allZWaveDevices == null)
+ throw new NullPointerException("I sensori non sono stati trovati");
+
if(nodeId != null)
useNode(nodeId);
else
@@ -94,7 +97,10 @@ public class Sensor {
synchronized public void update(int timeout) throws InterruptedException {
wait(timeout);
for (Device device : devices.getAllDevices())
- device.update();
+ try {
+ device.update();
+ } catch (Exception e) {}
+
wait(timeout);
}
/*
diff --git a/src/main/java/main/Main.java b/src/main/java/main/Main.java
index 504db51..9dec698 100644
--- a/src/main/java/main/Main.java
+++ b/src/main/java/main/Main.java
@@ -5,6 +5,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import support.Database;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
/**
* Created by 20015159 on 28/08/2018.
*/
@@ -15,34 +20,56 @@ public class Main {
*/
private static final Logger LOG = LoggerFactory.getLogger("SeniorAssistant");
- private static Hue lights;
- private static Fitbit fitbit;
- private static Sensor sensor;
+ private static Hue lights = null;
+ private static Fitbit fitbit = null;
+ private static Sensor sensor = null;
/**
* 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) {
+ Map arguments = getArgsMap(args);
- LOG.info("Connecting to hue lights");
- lights = new Hue();
-
- LOG.info("Connecting to the sensors");
- sensor = new Sensor(2);
+ // list of arguments to use in the classes
+ String hueAddress = arguments.get("hueAddress");
+ String hueUser = arguments.get("hueUser");
+ Integer sensorLog = getInt(arguments.get("sensorLog"));
+ Integer sensorNode = getInt(arguments.get("sensorNode"));
try {
- LOG.info("Connecting to Fitbit");
- fitbit = new Fitbit();
+ LOG.info("Connessione alle Philips Hue...");
+ lights = new Hue(hueAddress, hueUser);
- startInsertData();
- // add here functions associated with fitbit
- } catch (Exception e) { // in this way the program will continue even without fitbit
- e.printStackTrace();
+ try {
+ LOG.info("Connessione ai sensori...");
+ sensor = new Sensor(sensorNode);
+
+ if(sensorLog>0)
+ startSensorLog(sensorLog);
+ } catch (Exception e) {
+ LOG.warn(e.getMessage());
+ }
+
+ try {
+ LOG.info("Connessione al Fitbit, ignorare eventuale errore per setPermissionsToOwnerOnly...");
+ fitbit = new Fitbit();
+
+ startInsertData();
+ startCheckSteps();
+ startHueControlledByHeartBeat();
+ startWarnIfHeartBeatDrops();
+ } catch (Exception e) {
+ LOG.warn("Non e' stato possibile collegarsi al fitbit");
+ e.printStackTrace();
+ }
+
+ startHueAutoBrightness();
+ startWebhook();
+ } catch (Exception e) {
+ LOG.error(e.getMessage());
}
-
- startSensorLog(10);
- startWebhook();
+ LOG.info("FINE MAIN");
}
/**
@@ -117,6 +144,42 @@ public class Main {
thread.start();
}
+ // TODO AUTO:{B} Gestione luci in modo che la luminosità sia sempre la stessa
+ private static void startHueAutoBrightness() {
+ // controllare la luminosita' arrivata dal sensore
+ // trovare un valore di default per ogni ora
+ // se troppo bassa alzare la luci di poco
+ // se troppo alta abbassare le luci
+ // se l'utente modifica la luminosita' delle luci allora non fare nulla per almeno 20/30 minuti o di piu
+ }
+
+ // TODO AUTO:{C} Gestione luci a seconda del battito cardiaco
+ private static void startHueControlledByHeartBeat() {
+ // ad ogni X minuti:
+ // prendere la media di battiti di quell'ora dal DB
+ // prendere dal fitbit i valori degli ultimi X minuti
+ // controllare che non differiscano di un valore Delta
+ // se differiscono di almeno Delta modificare le luci abbassandole o alzandole secondo le esigenze
+ // (nel caso modificare anche il colore e renderlo meno intenso o di piu)
+ }
+
+ // TODO AUTO:{D} Ad una certa ora guarda i passi e se sono pochi dillo
+ private static void startCheckSteps() {
+ // 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)
+ }
+
+ // TODO AUTO:{E} Se i battiti sono troppo bassi/alti avvisare il tizio
+ private static void startWarnIfHeartBeatDrops() {
+ // controllare gli ultimi X minuti del fitbit
+ // tenersi una lista degli ultimi Y risultati
+ // controllare l'andamento dei battiti
+ // se troppo bassi o alti secondo un Delta, allora inviare un messaggio (DialogFlow?)
+ // (e' possibile integrarlo con la gestione delle luci tramite il battito)
+ }
+
/*
TODO AUTOMATIC: {B}, {C}, {D}, {E}
@@ -134,4 +197,37 @@ public class Main {
// Randomly at night heavy metal start
*/
+
+ /* ------------------------------------------------------------------------------------
+ Le funzioni qui sotto servono solamente per gli argomenti passati al main
+ ------------------------------------------------------------------------------------ */
+
+ /**
+ * Prende gli argomenti nel formato "-(.+)::(.+)" e li inserisce in una mappa.
+ * Se l'argomento non e' nel formato giusto lo ignora.
+ * @param args un'array di stringhe contente i vari argomenti
+ * @return una mappa con key il nome dell'argomento (la parte prima del :: e dopo il meno) e come valore il valore di esso (la parte dopo ::)
+ */
+ private static Map getArgsMap(String[] args) {
+ Map map = new HashMap<>();
+ Pattern pattern = Pattern.compile("-(.+)::(.+)");
+
+ for (String arg: args) {
+ Matcher matcher = pattern.matcher(arg);
+ if (matcher.find())
+ map.put(matcher.group(1), matcher.group(2));
+ }
+ return map;
+ }
+
+ /**
+ * Funzione creata per gli argomenti che vengono passati in modo da evitare millemila try and catch
+ * @param num la stringa da trasformare in numero
+ * @return il numero trasformato, null se fallisce
+ */
+ private static Integer getInt(String num) {
+ Integer returnNum = null;
+ try { returnNum = Integer.parseInt(num); } catch (Exception e) {}
+ return returnNum;
+ }
}
diff --git a/src/main/java/support/Rest.java b/src/main/java/support/Rest.java
index fc9b03d..80f8966 100644
--- a/src/main/java/support/Rest.java
+++ b/src/main/java/support/Rest.java
@@ -3,6 +3,7 @@ package support;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
+
import com.google.gson.Gson;
import org.apache.http.HttpResponse;
@@ -13,15 +14,22 @@ import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
/**
- * A generic class to perform HTTP calls and parse the resulting JSON.
- *
- * @author Luigi De Russis
- * @version 1.0 (18/05/2017)
+ * Una classe generica che invia delle richieste Rest e le parsifica nel JSON corrispondente
*/
public class Rest {
- // init gson
+ /**
+ * Un logger per vedere quando le richieste falliscono
+ */
+ private static final Logger LOG = LoggerFactory.getLogger("Rest");
+
+ /**
+ * Un GSON utile per il parsing della risposta
+ */
private static final Gson gson = new Gson();
/**
@@ -31,14 +39,12 @@ public class Rest {
* @return the response, parsed from JSON
*/
public static Map get(String URL) {
- // init
Map response = new HashMap<>();
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet request = new HttpGet(URL);
- CloseableHttpResponse result = null;
-
+ CloseableHttpResponse result;
try {
result = httpclient.execute(request);
String json = EntityUtils.toString(result.getEntity());
@@ -48,7 +54,7 @@ public class Rest {
result.close();
httpclient.close();
} catch (IOException e) {
- e.printStackTrace();
+ LOG.error("GET: " + e.getMessage());
}
return response;
@@ -62,11 +68,10 @@ public class Rest {
* @param contentType the content type of the request
*/
public static void put(String URL, String contentBody, String contentType) {
- // init
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpPut request = new HttpPut(URL);
- StringEntity params = null;
+ StringEntity params;
try {
params = new StringEntity(contentBody);
request.addHeader("content-type", contentType);
@@ -76,7 +81,7 @@ public class Rest {
// should be in finally...
httpclient.close();
} catch (Exception e) {
- e.printStackTrace();
+ LOG.error("PUT: " + e.getMessage());
}
}