Auto Brightness

- Hue now thread safe
- Added the auto-brightness
  * probably realistic enough
  * probably a bit buggy
- Added test for it
- Rearranged imports
This commit is contained in:
2018-09-17 12:54:20 +02:00
parent afe644c9e7
commit e5237b5da4
12 changed files with 189 additions and 155 deletions

View File

@@ -11,7 +11,12 @@
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
<excludeFolder url="file://$MODULE_DIR$/.idea" />
<excludeFolder url="file://$MODULE_DIR$/.settings" />
<excludeFolder url="file://$MODULE_DIR$/META-INF" />
<excludeFolder url="file://$MODULE_DIR$/build" />
<excludeFolder url="file://$MODULE_DIR$/gradle" />
<excludeFolder url="file://$MODULE_DIR$/lib" />
<excludeFolder url="file://$MODULE_DIR$/out" />
</content>
<orderEntry type="sourceFolder" forTests="false" />

View File

@@ -1,14 +1,15 @@
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;
import ai.api.GsonFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import support.Rest;
/**
* Classe che permette di controllare le luci Philips Hue
*/
@@ -22,12 +23,12 @@ public class Hue {
/**
* La luminopsita' massima a cui si puo' arrivare
*/
public static final int MAX_BRIGHTNESS = 254;
private 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<>();
private static final Map<String, Double[]> COLORS = new HashMap<>();
/**
* L'url in cui si possono trovare le luci
@@ -42,11 +43,9 @@ public class Hue {
/**
* L'ultima luminosita' impostata
*/
private double brightness = 0;
private final AtomicDouble brightness = new AtomicDouble(0);
/**
* Riempimento della mappa con i vari colori
*/
// 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});
@@ -96,7 +95,7 @@ public class Hue {
map.put("hue", (int)hue);
setState(map);
brightness = (bri*MAX_BRIGHTNESS)/100;
brightness.set((bri*MAX_BRIGHTNESS)/100);
}
/**
@@ -134,9 +133,9 @@ public class Hue {
/**
* Ritorna la liminosita' attuale delle luci controllate
* @return
* @return il valore e' compreso tra 0 e 100
*/
public double getCurrentBrightness() { return brightness; }
public double getCurrentBrightness() { return brightness.doubleValue(); }
/**
* Modifica la luminosita' delle luci a seconda del valore inserito
@@ -149,7 +148,15 @@ public class Hue {
num=100;
setState("bri", (int) (num*MAX_BRIGHTNESS)/100 );
brightness = num;
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);
}
/**
@@ -161,7 +168,7 @@ public class Hue {
percentage = 0;
else if (percentage>100)
percentage = 100;
setBrightness(brightness + percentage);
setBrightness(brightness.doubleValue() + percentage);
}
/**
@@ -178,7 +185,7 @@ public class Hue {
percentage = 0;
else if (percentage>100)
percentage = 100;
setBrightness(brightness - percentage);
setBrightness(brightness.doubleValue() - percentage);
}
/**
@@ -226,7 +233,7 @@ public class Hue {
* Invia una richiesta a tutte le luci hue con gli attributi selezionati ed il loro valore
* @param attributes una mappa di attributi -> valori
*/
public void setState(Map<String, Object> attributes) {
public synchronized void setState(Map<String, Object> attributes) {
String body = GsonFactory.getDefaultFactory().getGson().toJson(attributes);
LOG.info("Setting: " + body);
for (String light : allLights.keySet()) {

View File

@@ -80,29 +80,24 @@ public class Sensor {
/**
* Legge i valori della luminosita' segnata dai dispositivi e ne ritorna il valore
* @return la luminopsita' segnata dai dispositivi
* @return la luminosita' segnata dai dispositivi (da 0 a 100)
*/
public int getBrightnessLevel() {
public double getBrightnessLevel() {
update();
for (Device device : devices.getAllDevices())
if (device.getMetrics().getProbeTitle().equalsIgnoreCase("luminiscence"))
return Integer.parseInt(device.getMetrics().getLevel());
return -99;
return Double.parseDouble(device.getMetrics().getLevel())/10;
return 0;
}
/**
* Fa in modo di forzare l'aggiornamento dei dispositivi
* @param timeout fa aspettare un tot di tempo prima di provare a forzare e dopo l'aggiornameto
*/
synchronized public void update(int timeout) {
try {
wait(timeout / 2);
synchronized private void update() {
for (Device device : devices.getAllDevices())
try {
device.update();
} catch (Exception e) { }
wait(timeout / 2);
} catch (InterruptedException e) { }
}
/*
public boolean IsLowLuminescence(int Luminescence) {

View File

@@ -3,7 +3,6 @@ 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;
@@ -52,7 +51,7 @@ public class Sleep {
public final long start_date;
public final long duration;
public SleepData(Date start_date, long duration) {
SleepData(Date start_date, long duration) {
this.start_date = start_date.getTime();
this.duration = duration;
}

View File

@@ -1,6 +1,10 @@
package main;
import device.*;
import device.Fitbit;
import device.Hue;
import device.Sensor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import support.database.Database;
import support.database.LocalDB;
import support.database.RemoteDB;
@@ -16,6 +20,11 @@ import java.util.regex.Pattern;
*/
public class SeniorAssistant {
/**
* Un Logger per capire meglio quali pezzi vengono eseguiti e quali no.
*/
public static final Logger LOG = LoggerFactory.getLogger("SeniorAssistant");
/**
* Funzione principale, qui si creano tutte le classi che verranno utilizzate.<br>
* Si possono passare dei parametri usando -(nome parametro)::(valore parametro)<br>
@@ -25,6 +34,7 @@ public class SeniorAssistant {
* <li>hueAddress</li>
* <li>hueUser</li>
* <li>sensorAddress</li>
* <li>autoBrightness</li>
* <li>sensorNode</li>
* <li>remoteDbUser</li>
* </ul>
@@ -35,57 +45,58 @@ public class SeniorAssistant {
Map<String, String> arguments = getArgsMap(args);
// list of arguments to use in the classes
String hueAddress = arguments.get("hueAddress");
String hueUser = arguments.get("hueUser");
String hueAddress = arguments.get("hueaddress");
String hueUser = arguments.get("hueuser");
//TODO String sensorAddress = arguments.get("sensorAddress");
Integer sensorNode = getInt(arguments.get("sensorNode"));
String remoteDbUser = arguments.get("remoteDbUser");
Integer sensorNode = getInt(arguments.get("sensornode"));
String remoteDbUser = arguments.get("remotedbuser");
boolean autoBrightness = arguments.containsKey("autobrightness");
try {
VariousThreads.LOG.info("Connessione alle Philips Hue...");
LOG.info("Connessione alle Philips Hue...");
Hue lights = new Hue(hueAddress, hueUser);
try {
VariousThreads.LOG.info("Connessione ai sensori...");
if(autoBrightness) try {
LOG.info("Connessione ai sensori...");
Sensor sensor = new Sensor(sensorNode);
threads.startHueAutoBrightness(lights, sensor);
} catch (Exception e) {
VariousThreads.LOG.warn(e.getMessage());
LOG.warn(e.getMessage());
}
try {
VariousThreads.LOG.info("Connessione al Fitbit, ignorare eventuale errore per setPermissionsToOwnerOnly...");
LOG.info("Connessione al Fitbit, ignorare eventuale errore per setPermissionsToOwnerOnly...");
Fitbit fitbit = new Fitbit();
VariousThreads.LOG.info("Connessione al database...");
LOG.info("Connessione al database...");
Database database = remoteDbUser == null ? new LocalDB() : new RemoteDB(remoteDbUser);
threads.startInsertData(database, fitbit);
threads.startHueControlledByHeartBeat(lights, fitbit, database);
threads.startCheckSteps(fitbit);
} catch (Exception e) {
VariousThreads.LOG.warn("Non e' stato possibile collegarsi al fitbit");
LOG.warn("Non e' stato possibile collegarsi al fitbit");
e.printStackTrace();
}
threads.startWebhook(lights);
} catch (Exception e) {
VariousThreads.LOG.error(e.getMessage());
LOG.error(e.getMessage());
}
VariousThreads.LOG.info("FINE MAIN");
LOG.info("FINE MAIN");
}
/*
TODO AUTOMATIC: {B}, {D}
TODO AUTOMATIC: {D}
XXX Gestione DB in modo che si aggiorni ogni ora
/B/ Gestione luci in modo che la luminosità sia sempre la stessa
XXX Gestione luci in modo che la luminosità sia sempre la stessa
XXX Gestione luci a seconda del battito cardiaco
/D/ Ad una certa ora guarda i passi e se sono pochi dillo
/D/ Ogni X ore/minuti guarda i passi e se sono pochi dillo
XXX Se i battiti sono troppo bassi/alti avvisare il tizio
TODO USER-INTERACTION {A}, {C}
TODO USER-INTERACTION {A}
/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 )
@@ -118,7 +129,7 @@ public class SeniorAssistant {
for (String arg: args) {
Matcher matcher = pattern.matcher(arg);
if (matcher.find())
map.put(matcher.group(1), matcher.group(2));
map.put(matcher.group(1).toLowerCase(), matcher.group(2));
}
return map;
}

View File

@@ -5,27 +5,30 @@ import device.Fitbit;
import device.Hue;
import device.Sensor;
import device.fitbitdata.HeartRate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import support.Musich;
import support.database.Database;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class VariousThreads {
/**
* Un Logger per capire meglio quali pezzi vengono eseguiti e quali no.
*/
public static final Logger LOG = LoggerFactory.getLogger("SeniorAssistant");
/**
* Una costante che indica quanti millisecondi ci sono in un minuto (utile per le conversioni)
*/
public static final int MILLISEC_IN_MINUTE = 60000;
/**
* Quanti minuti di cooldown da impostare dopo che l'utente ha chiesto di modificare le luci
*/
private static final int COOLDOWN_IN_MINUTES = 20;
/**
* Variabile che serve ad impostare un cooldown per la luminosita' automatica
*/
private final AtomicInteger cooldown = new AtomicInteger(0);
/**
* La variabile per far partire della musica da Youtube
@@ -47,8 +50,8 @@ public class VariousThreads {
public void startWebhook(final Hue lights) {
DialogFlowWebHook df = new DialogFlowWebHook();
df.addOnAction("LightsON", (params) -> { lights.turnOn(); return null; });
df.addOnAction("LightsOFF", (params) -> { lights.turnOff(); return null; });
df.addOnAction("LightsON", (params) -> { lights.turnOn(); cooldown.set(COOLDOWN_IN_MINUTES); return null; });
df.addOnAction("LightsOFF", (params) -> { lights.turnOff(); cooldown.set(COOLDOWN_IN_MINUTES); return null; });
df.addOnAction("ColorLoop", (params) -> { lights.colorLoop(); return null; });
df.addOnAction("ChangeColor", (params) -> {
lights.changeColor(params.get("color").getAsString());
@@ -56,6 +59,7 @@ public class VariousThreads {
});
df.addOnAction("SetLights", (params) -> {
lights.setBrightness(params.get("intensity").getAsInt());
cooldown.set(COOLDOWN_IN_MINUTES);
return null;
});
df.addOnAction("LightsDOWN", (params) -> {
@@ -63,6 +67,7 @@ public class VariousThreads {
lights.decreaseBrightness();
else
lights.decreaseBrightness(params.get("intensity").getAsInt());
cooldown.set(COOLDOWN_IN_MINUTES);
return null;
});
df.addOnAction("LightsUP", (params) -> {
@@ -70,6 +75,7 @@ public class VariousThreads {
lights.increaseBrightness();
else
lights.increaseBrightness(params.get("intensity").getAsInt());
cooldown.set(COOLDOWN_IN_MINUTES);
return null;
});
df.addOnAction("SetMusic", (param) -> {
@@ -82,7 +88,7 @@ public class VariousThreads {
//TODO aggiungere una azione su DialogFlow che riconosca di impostare una playlist (Rilassante, Antica...)
df.startServer();
LOG.info("Webhook partito");
SeniorAssistant.LOG.info("Webhook partito");
}
/**
@@ -99,13 +105,12 @@ public class VariousThreads {
hourlyData.start();
dailyData.start();
LOG.info("Thread per gli aggiornamenti automatici partiti");
SeniorAssistant.LOG.info("Thread per gli aggiornamenti automatici partiti");
} catch (Exception e) {
e.printStackTrace();
}
}
// TODO fare auto-brightness
/**
* Gestione delle luci in modo che cambiano la luminosita' in base ai dati ricevuti dal sensore<br>
* Se l'utente pero' cambia il valore delle luci di sua volonta', il processo non modifichera' le luci per almeno un'ora.
@@ -113,55 +118,29 @@ public class VariousThreads {
* @param sensor i sensori da cui porendere i dati
*/
public void startHueAutoBrightness(final Hue lights, final Sensor sensor) {
// 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
/*
Thread thread = new Thread(new Runnable() {
@Override
public synchronized void run() {
boolean notInterrupted = true;
final int minute = 1;
final int minBrightness = 20; // valore che va da 0 a 100
Calendar calendar = Calendar.getInstance();
while(notInterrupted) {
int bright = sensor.getBrightnessLevel();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
if(hour >= 21 && hour<7) {
lights.setBrightness(5);
}
else if(hour >= 19 && hour<21) {
lights.setBrightness(99);
}
else if(hour >= 7 && hour<19) {
lights.setBrightness(0);
}
Thread thread = getThreadStartingEach(() -> {
if(cooldown.addAndGet(-minute) <= 0) {
calendar.setTimeInMillis(System.currentTimeMillis());
try {
wait(120000);
} catch (InterruptedException e) {
e.printStackTrace();
notInterrupted = false;
}
if(hour >= 21 && hour<7)
lights.setBrightness(5);
else if(bright >= 0 && bright <= 20)
lights.setBrightness(90);
else if(bright >= 21 && bright <= 40)
lights.setBrightness(60);
else if(bright >= 41 && bright <= 60)
lights.setBrightness(40);
else
lights.turnOff();
// puo' avere un valore compreso tra -1 e 1
final double brightFactor =
calculateBrightFactor(
calendar.get(Calendar.HOUR_OF_DAY),
calendar.get(Calendar.MINUTE),
sensor.getBrightnessLevel()/10,
minBrightness
);
lights.addBrightness(brightFactor*100);
}
}
}, "auto-brightness");
}, minute, "auto-brightness");
thread.start();
*/
SeniorAssistant.LOG.info("Thread per l'impostazione automatica della luminosita' partito");
}
/**
@@ -174,10 +153,10 @@ public class VariousThreads {
public void startHueControlledByHeartBeat(final Hue lights, final Fitbit fitbit, final Database database) {
final int minutes = 30;
final int delta = 15;
Runnable runnable = new Runnable() {
Thread thread = getThreadStartingEach(new Runnable() {
@Override
public synchronized void run() {
int sum=0;
double sum=0;
int count=0;
double average;
@@ -205,10 +184,10 @@ public class VariousThreads {
//avvisare con una voce registrata?
;
}
};
}, minutes, "lights-with-heartbeat");
getThreadStartingEach(runnable, minutes, "lights-with-heartbeat").start();
LOG.info("Thread per il controllo delle luci tramite il battito cardiaco partito");
thread.start();
SeniorAssistant.LOG.info("Thread per il controllo delle luci tramite il battito cardiaco partito");
}
// TODO Ad una certa ora guarda i passi e se sono pochi dillo
@@ -227,6 +206,31 @@ public class VariousThreads {
/**
* Calcola un numero compreso fra -1 e 1 che indica se c'e' bisogno o meno di luminosita'<br>
* Se i valori inseriti sono maggiori o minori di quelli consentiti, allora verranno limitati<br>
* ovvero se sono minori del minimo esso diventera' il minimo, stessa cosa con il massimo.
* @param hour l'ora corrente (valore da 0 a 23)
* @param minutes i minuti correnti (valore da 0 a 59)
* @param sensorBright la liminosita' segnata dal sensore (valore da 0 a 100)
* @param minBrightness la luminosita' minima che si vuole avere (valore da 0 a 100)
* @return un valore indicante quanta luminosita' si ha bisogno nell'ora indicata e con la luminosita' indicata
*/
public static double calculateBrightFactor(int hour, int minutes, double sensorBright, double minBrightness) {
hour = hour<0? 0:hour>23? 23:hour;
minutes = minutes<0? 0:minutes>59? 59:minutes;
minBrightness = minBrightness<0? 0:minBrightness>100? 100:minBrightness;
sensorBright = sensorBright<0? 0:sensorBright>100? 100:sensorBright;
// Valore compreso tra -1(poca luminosita') e 1(molta luminosita')
sensorBright = sensorBright/100;
minBrightness = 0.5*Math.abs(1-minBrightness/100);
// Puo' avere un valore compreso tra 1(mezzanotte) e 0(mezzogiorno) => il valore minimo(0) puo' aumentare grazie a minBrightness)
final double maxIntensity = minBrightness*Math.cos((2*Math.PI*(hour + (minutes/60.0)) /24)) + (1-minBrightness);
return maxIntensity-sensorBright;
}
/**
* Restuisce un thread che se fatto partire, esegue il runnable in un sub-thread ogni X minuti<br>

View File

@@ -1,19 +1,11 @@
package oauth;
import java.io.IOException;
import java.util.Arrays;
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.http.BasicAuthentication;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpRequest;
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.*;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.JsonObjectParser;
@@ -23,6 +15,9 @@ import com.google.api.client.util.store.FileDataStoreFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Arrays;
/**
* Classe piu' importante per la connessione al fitbit
*/

View File

@@ -1,11 +1,6 @@
package support;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import com.google.gson.Gson;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
@@ -17,6 +12,9 @@ import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
/**
* Una classe generica che invia delle richieste Rest e le parsifica nel JSON corrispondente
*/

View File

@@ -18,7 +18,6 @@ import de.fh_zwickau.informatik.sensor.model.profiles.ProfileList;
import de.fh_zwickau.informatik.sensor.model.zwaveapi.controller.ZWaveController;
import de.fh_zwickau.informatik.sensor.model.zwaveapi.devices.ZWaveDevice;
import device.Sensor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@@ -1,2 +1,2 @@
org.slf4j.simpleLogger.defaultLogLevel=info
org.slf4j.simpleLogger.defaultLogLevel=warn
org.slf4j.simpleLogger.logFile=System.out

View File

@@ -2,47 +2,55 @@ package test;
import ai.api.GsonFactory;
import device.Hue;
import main.VariousThreads;
import org.junit.Before;
import org.junit.Test;
import java.util.HashSet;
import java.util.Set;
public class TestLights {
public static final int TIMEOUT = 200;
private static final int TIMEOUT = 200;
private static final int MAX = 100;
private Hue lights;
@Before
public void init() {
lights = new Hue();
lights.turnOn();
lights.setBrightness(100);
lights.changeColor("bianco");
}
@Test
synchronized public void firstTestLights() throws InterruptedException {
Hue lights = new Hue();
Set<String> toRemove = new HashSet<>();
for(String str: lights.getNameLights())
if(!(Integer.parseInt(str)%2 == 0))
toRemove.add(str);
lights.removeLights(toRemove);
for(int i=0; i<10; i++) {
for (int i = 0; i < 10; i++) {
lights.turnOn();
this.wait(TIMEOUT);
lights.turnOff();
this.wait(TIMEOUT);
}
}
lights.turnOn();
for(int i=Hue.MAX_BRIGHTNESS; i>0; i-=10) {
@Test
synchronized public void testBrightness() throws InterruptedException {
for (int i = MAX; i > 0; i -= 10) {
lights.setBrightness(i);
this.wait(TIMEOUT);
}
for(int i=0; i<Hue.MAX_BRIGHTNESS; i+=10) {
for (int i = 0; i < MAX; i += 10) {
lights.setBrightness(i);
this.wait(TIMEOUT);
}
}
lights.setBrightness(Hue.MAX_BRIGHTNESS);
@Test
synchronized public void testColorLoop() throws InterruptedException {
lights.colorLoop();
this.wait(TIMEOUT*10);
this.wait(TIMEOUT * 10);
}
@Test
synchronized public void testColor() throws InterruptedException {
// change colors
for (int i=0; i<=360; i++) {
double radian = (0.0174533*i);
@@ -51,7 +59,22 @@ public class TestLights {
lights.setState("xy", GsonFactory.getDefaultFactory().getGson().toJson(new Double[]{x, y}));
this.wait(TIMEOUT);
}
}
@Test
synchronized public void testAutoBright() throws InterruptedException {
lights.setBrightness(MAX);
for(int hour=0; hour<24; hour++)
for(int minutes=0; minutes<60; minutes++) {
final double hueBrightnes = lights.getCurrentBrightness();
final double brightFactor = VariousThreads.calculateBrightFactor(hour, minutes, 100, 20);
final double bright = brightFactor*100;
System.out.printf("%2d:%02d: %+.3f {bri:%3.0f -> add:%+4.0f}\n", hour, minutes, brightFactor, hueBrightnes, bright);
lights.addBrightness(bright);
wait(TIMEOUT);
}
}
}

View File

@@ -8,17 +8,16 @@ import java.util.HashSet;
import java.util.Set;
public class TestSensor {
Sensor sensor = new Sensor(2);
Hue lights;
private Sensor sensor = new Sensor(2);
private Hue lights;
@Test
synchronized public void firstTestSensor() throws InterruptedException {
sensor.update(2);
synchronized public void firstTestSensor() {
System.out.println(sensor.getBrightnessLevel());
}
@Test
synchronized public void secondTestSensor() throws InterruptedException {
synchronized public void secondTestSensor() {
int i=0;
lights = new Hue();
Set<String> toRemove = new HashSet<>();
@@ -39,7 +38,6 @@ import java.util.Set;
lights.setBrightness(0);
}
System.out.println(i+"-"+sensor.getBrightnessLevel());
sensor.update(100);
i++;
}
}