Files
upo-senior-assistant-pi/src/main/java/device/Hue.java
Giacomo e5237b5da4 Auto Brightness
- Hue now thread safe
- Added the auto-brightness
  * probably realistic enough
  * probably a bit buggy
- Added test for it
- Rearranged imports
2018-09-17 12:54:20 +02:00

248 lines
8.3 KiB
Java

package device;
import ai.api.GsonFactory;
import com.google.common.util.concurrent.AtomicDouble;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import support.Rest;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Classe che permette di controllare le luci Philips Hue
*/
public class Hue {
/**
* Log che serve per debug
*/
private static final Logger LOG = LoggerFactory.getLogger("Hue");
/**
* La luminopsita' massima a cui si puo' arrivare
*/
private static final int MAX_BRIGHTNESS = 254;
/**
* Una mappa che ad ogni colore (in lingua ita) assegna il proprio valore in hue
*/
private static final Map<String, Double[]> COLORS = new HashMap<>();
/**
* L'url in cui si possono trovare le luci
*/
private final String lightsURL;
/**
* Tutte le luci che sono state registrate dall'url
*/
private final Map<String, Map<String, Object>> allLights;
/**
* L'ultima luminosita' impostata
*/
private final AtomicDouble brightness = new AtomicDouble(0);
// Riempimento della mappa con i vari colori
static {
COLORS.put("giall[oae]", new Double[]{0.45, 0.45});
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.12, 0.125});
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.55, 0.4});
//COLORS.put("nero", new Double[]{1.0, 1.0});
COLORS.put("bianc(o|a|he)", new Double[]{0.275, 0.3});
}
/**
* 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>
* @throws NullPointerException se non trova nessun bridge
*/
public Hue () throws NullPointerException { this("172.30.1.138", "C0vPwqjJZo5Jt9Oe5HgO6sBFFMxgoR532IxFoGmx"); }
/**
* 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
* @throws NullPointerException se non trova nessun bridge
*/
public Hue(String ip, String user) throws NullPointerException {
lightsURL = "http://" + ip + "/api/" + user + "/lights/";
allLights = (Map<String, Map<String, Object>>)Rest.get(lightsURL);
if(allLights.isEmpty())
throw new NullPointerException("Non e' stato possibile connettersi alle luci");
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();
Map<String, Object> map = new HashMap<>();
map.put("bri", (int)bri);
map.put("hue", (int)hue);
setState(map);
brightness.set((bri*MAX_BRIGHTNESS)/100);
}
/**
* Ritorna un insieme contenente tutti i nomi delle luci che si sono trovate
*
* @return l'insieme dei nomi delle luci
*/
public Set<String> getNameLights() { return allLights.keySet(); }
/**
* Rimuove dal controllo tutte le luci che hanno il nome uguale ad uno contenuto nell'insieme passato
*
* @param toRemove le luci da rimuovere
*/
public void removeLights(Set<String> toRemove) {
for(String string : toRemove)
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() { on(true); }
/**
* Spegne tutte le luci controllate
*/
public void turnOff() { on(false); }
/**
* Ritorna la liminosita' attuale delle luci controllate
* @return il valore e' compreso tra 0 e 100
*/
public double getCurrentBrightness() { return brightness.doubleValue(); }
/**
* Modifica la luminosita' delle luci a seconda del valore inserito
* @param num la luminosita' che si vuole da (0 a 100)
*/
public void setBrightness(double num) {
if (num<0)
num=0;
else if (num>100)
num=100;
setState("bri", (int) (num*MAX_BRIGHTNESS)/100 );
brightness.set(num);
}
/**
* Aggiunge il valore delta alla luminosita' corrente delle luci.
* @param delta un qualsiasi numero che va da -100 a 100
*/
public void addBrightness(double delta) {
setBrightness(brightness.doubleValue() + delta);
}
/**
* Aumenta la luminosita' delle luci controllate della percentuale che viene passata
* @param percentage la percentuale di aumento della luminosita'
*/
public void increaseBrightness(double percentage) {
if (percentage<0)
percentage = 0;
else if (percentage>100)
percentage = 100;
setBrightness(brightness.doubleValue() + percentage);
}
/**
* Aumenta la luminosita' delle luci controllate del 25%
*/
public void increaseBrightness() { increaseBrightness(25); }
/**
* Dinuisce la luminosita' delle luci controllate della percentuale che viene passata
* @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.doubleValue() - percentage);
}
/**
* Dinuisce la luminosita' delle luci controllate del 25%
*/
public void decreaseBrightness() { decreaseBrightness(25); }
public void changeColor(String colorName) {
for (String regex: COLORS.keySet())
if(colorName.matches("(?i)" + regex))
setState("xy", COLORS.get(regex));
}
/**
* Modifica il colore delle luci in modo da fare un bel effetto arcobaleno continuo
*/
public void colorLoop() { setState("effect", "colorloop"); }
/**
* Invia una richiesta a tutte le luci hue con l'attributo selezionato ed il suo valore<br>
* Con esso invia anche una transition:20 in modo che sia piu fluido il cambiamento
* @param attribute l'attributo che si vuole cambiare
* @param value il valore da inserire
*/
public void setState(String attribute, Object value){
setState(attribute, value, true);
}
/**
* Invia una richiesta a tutte le luci hue con l'attributo selezionato ed il suo valore<br>
* Con esso invia anche una transition:20 in modo che sia piu fluido il cambiamento se si mette true al terzo parametro
* @param attribute l'attributo da modificare
* @param value il valore da inserire
* @param transition se includere la transizione o meno
*/
public void setState(String attribute, Object value, boolean transition){
Map<String, Object> map = new HashMap<>();
map.put(attribute, value);
if(transition)
map.put("transition", 200);
setState(map);
}
/**
* Invia una richiesta a tutte le luci hue con gli attributi selezionati ed il loro valore
* @param attributes una mappa di attributi -> valori
*/
public synchronized void setState(Map<String, Object> attributes) {
String body = GsonFactory.getDefaultFactory().getGson().toJson(attributes);
LOG.info("Setting: " + body);
for (String light : allLights.keySet()) {
Rest.put(lightsURL + light + "/state", body,"application/json");
Map<String, Object> state = (Map<String, Object>)allLights.get(light).get("state");
for (String attr : attributes.keySet())
state.put(attr, attributes.get(attr));
}
}
}