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 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> 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 http://172.30.1.138/api/C0vPwqjJZo5Jt9Oe5HgO6sBFFMxgoR532IxFoGmx/lights/ * @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.
* Una volta trovate le luci le setta tutte alla stessa luminosita' e allo stesso colore
* (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>)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 state = (Map)allLights.get(name).get("state"); bri += (Double) state.get("bri"); hue += (Double) state.get("hue"); } bri = bri/allLights.size(); hue = hue/allLights.size(); Map 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 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 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
* 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
* 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 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 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 state = (Map)allLights.get(light).get("state"); for (String attr : attributes.keySet()) state.put(attr, attributes.get(attr)); } } }