Testen met licht
Licht is een van de drijvende krachten van ons bioritme, doordat het de melatonine-productie kan beïnvloeden. Er zijn echter nog al wat variabelen om te testen. In dit verzamel artikel geeft een overzicht van alle testen die ik heb uitgevoerd.
Inhoud
Spring direct naar een onderwerp...
Mimic the sun
In veel literatuur kwam ik tegen dat een lichtsysteem het beste in het voordeel van je bioritme werkt als het de zon na doet. Dit klinkt vrij logisch en snel uitgezocht, maar niks is minder waar. Het blijkt ingewikkeld te zijn om uit te vinden welke gevolgen de zon precies heeft op het licht zoals wij dat ervaren op de aarde. En dan heb ik het nog niet eens over welke gevolgen dat licht vervolgens heeft op ons.
Licht temperatuur
De licht temperatuur (in dit geval de Correlated Color Temperature) van de zon verandert over de loop van de dag vanwege een natuurkundig principe genaamd Reyleigh scattering.
Rayleigh scattering heeft te maken met met het verschil in golflengte van de verschillende kleuren licht, waardoor in de atmosfeer van de aarde het blauwe spectrum makkelijker verstrooid wordt dan het rode spectrum. Dit zorgt er voor dat de lucht blauw wordt, de zon geel lijkt en dat zonsondergang en -opgang rood zijn.
Ik vroeg mij af hoe die verandering er ongeveer uit ziet op een schaal van kleurtemperatuur. Dus ik heb gezocht, maar kon het niet vinden. Toen ik er zelf niet uit kwam heb ik een vriend van mij ingeschakeld die docent natuurkunde is op een middelbare school, maar hij kon mij ook niet verder helpen. Ten slotte heb ik een mail gestuurd naar het KNMI als laatste strohalm.
Update mail KNMI
sluiten
Geachte heer,
Dank voor uw mail en interesse in het KNMI. Uw vraag lijkt ons echter meer op het gebied van lichttechnologie (> universiteit?) dan op dat van de meteorologie te liggen. En wellicht zou de publicatie van M. Minnaert: Natuurkunde van het vrije veld u meer kunnen leren?
Met vriendelijke groet,
Wouter ***
Informatiecentrum KNMI
Deze interessante bron heb ik bekeken, maar heeft helaas geen antwoord op mijn vraag. Het is simpelweg niet specifiek genoeg. Tijd voor plan B.
Als dat ook niet werkt zal ik mijn eigen observaties moeten gaan maken om hier een beeld van te krijgen. Daar ben ik voor een deel al mee begonnen. In de afbeelding hier onder zijn mijn eerste pogingen te zien om de temperatuur van de zon om te zetten in getallen. Met deze dataset ga ik testen.
Kleur sensor
Waarom heb ik hier niet eerder aan gedacht. Het is ondertussen maanden later en ik heb eindelijk een haalbare manier bedacht om de temperatuur van licht te meten.
In eerste instantie heb ik het zelf meten als onmogelijk beschouwd, omdat ik dacht hiervoor een optische spectrometer nodig te hebben. Deze apparaten zijn voor mij onbetaalbaar, ook de relatief goekope varianten.
Toen kwam ik toevallig terecht bij de TCS34725 sensor van Adafruit. Deze sensor heeft een ledje op zich. Als het ledje aanstaat en je een object boven de sensor houd, dan kan het onderscheiden welke kleur licht het object reflecteert. Oftewel: Welke kleur het object heeft. Omdat deze sensor de kleur van het gereflecteerde licht kan zien, kan het dat ook van direct licht. Bijvoorbeeld zonlicht.
De testopstelling gebruikt een Arduino Uno r3 en een Raspberry Pi 3 model B. De Arduino leest elke seconde de sensor uit en stuurt doet wat rekenwerk om de kleurtemperatuur en intensiteit te krijgen. Deze twee waardes stuurt de Arduino via USB door naar de Pi. De Pi plakt aan de data de huidige tijd en slaat het op in een log bestand.
Aan het eind van een meetperiode pluk ik het log bestand van de Pi en verwerk ik de data als .csv, waarschijnlijk in Tableau.
De testopstelling ziet er als volgt uit:
Foto's sensor setup
Sluiten
De sensor zoals het vast zit op een Arduino.
De sensor kijkt door het open raam naar de lucht.
De Arduino is aangesloten op de Raspberry Pi. De Pi slaat alle data van de sensor op. Daar is geen ruimte voor op de Arduino zelf, dus deze omweg is noodzakelijk.
En dit is de software:
Software Arduino—Arduino C
Sluiten
#include <Wire.h>
#include "Adafruit_TCS34725.h"
/* Example code for the Adafruit TCS34725 breakout library */
/* Connect SCL to analog 5
Connect SDA to analog 4
Connect VDD to 3.3V DC
Connect GROUND to common ground */
/* Initialise with default values (int time = 2.4ms, gain = 1x) */
// Adafruit_TCS34725 tcs = Adafruit_TCS34725();
/* Initialise with specific int time and gain values */
Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_1X);
byte set_measurements = 10; // Amount of readings per measurement
int vals[2] = {0,0}; // Output of measure()
long previousMillis = 0; // will store last time sensor was updated
long interval = 1000; // interval at which to blink (milliseconds)
void setup() {
Serial.begin(9600);
delay(1000);
if (tcs.begin()) {
Serial.println("Found sensor");
} else {
Serial.println("No TCS34725 found ... check your connections");
while (1);
}
// Now we're ready to get readings!
delay(500);
Serial.println("CT,Lux");
delay(500);
}
void loop() {
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
measure(vals);
// Serial.print("CT: ");
Serial.print(vals[0]);
Serial.print(",");
// Serial.print("Lux: ");
Serial.print(vals[1]);
Serial.println();
}
}
int* measure(int* vals) {
unsigned int ct=0;
unsigned int lux=0;
unsigned int r,g,b,c;
for(byte i=0; i<set_measurements; i++) {
tcs.getRawData(&r, &g, &b, &c);
ct += tcs.calculateColorTemperature(r, g, b);
lux += tcs.calculateLux(r, g, b);
delay(10);
}
vals[0] = ct / set_measurements;
vals[1] = lux / set_measurements;
}
Software Raspberry Pi—Processing Java
Sluiten
import processing.serial.*;
Serial myPort; // The serial port
int xPos = 1; // horizontal position of the graph
boolean logToFile = true;
PrintWriter logFile;
void setup () {
// set the window size:
size(10, 10);
logInit();
// List all the available serial ports
printArray(Serial.list());
// I know that the first port in the serial list on my mac
// is always my Arduino, so I open Serial.list()[0].
// Open whatever port is the one you're using.
myPort = new Serial(this, Serial.list()[3], 9600);
// don't generate a serialEvent() unless you get a newline character:
myPort.bufferUntil('\n');
// set inital background:
background(0);
}
void draw () {
// everything happens in the serialEvent()
}
void serialEvent (Serial myPort) {
// get the ASCII string:
String inString = myPort.readStringUntil('\n');
if (inString != null) {
// trim off any whitespace:
inString = trim(inString);
//println(inString);
logln(logPrefix()+inString);
}
}
// Functions below ported from Light prototype controller
/////////////////////////////////////////////////////////
String logPrefix() {
String ret = leadingZero(hour(), 1)+":"+
leadingZero(minute(), 1)+":"+
leadingZero(second(), 1)+",";
return ret;
}
// Open a file to write log data to
void logInit() {
// If we want to log in a file
if (logToFile) {
// Make a timestamp
String timestamp = leadingZero(day(), 1)+
leadingZero(month(), 1)+
year()+
"-"+
leadingZero(hour(), 1)+
leadingZero(minute(), 1);
// Create a new log file
logFile = createWriter("log/log-"+timestamp+".txt");
// Write open message to log
logln("Log opened at "+timestamp);
logln();
}
}
// replaces println(boolean)
void logln(boolean in) {
log(str(in)+"\n");
}
// replaces println(int)
void logln(int in) {
log(str(in)+"\n");
}
// replaces println(float)
void logln(float in) {
log(str(in)+"\n");
}
// replaces println(String)
void logln(String in) {
log(in+"\n");
}
// replaces println(Null)
void logln() {
log("\n");
}
// replaces print(String)
void log(String in) {
if (logToFile) {
logFile.print(in);
logFile.flush();
} else print(in);
}
//Adds leading zeroes to int and returns it as a String
String leadingZero(int in, int z) {
int lim=1;
String out = "";
for (int i=0; i<z; i++) {
lim *= 10;
if (in < lim && out == "") {
for (int j=0; j<(z-i); j++) {
out += "0";
}
out += in;
}
}
if (out == "") out = str(in);
return out;
}
Lampen
Om de zon na te doen moet je natuurlijk lampen hebben. Ik ga voor mijn tests een Philips Hue kit met 3 kleurlampen gebruiken. Deze lampen kunnen een licht temperatuur van 2000K (zonsopgang en zonsondergang) tot 6500K (zon op hoogste punt) bereiken, wat ze perfect maakt voor mijn doel.
Ik ga testen met alle drie de lampen aan mijn plafon (foto tbd) in mijn vrij kleine kamer. Hierdoor verwacht ik dat ik meer dan genoeg intensiteit beschikbaar heb om de zon na te bootsen. Ook kan ik makkelijk lampen uitschakelen om te testen hoe het effect is met minder intensiteit.
Op het moment van schrijven heb ik alles voorbereid om snel mijn huidige lampen te vervangen, maar de lampen zelf heb ik nog niet.
Ik ga Processing met bestaande code gebruiken om de lampen aan te sturen vanaf mijn computer.
Update: It's alive
Ondertussen heb ik de bestaande aangepast om veel flexibeler te zijn en om de input van een zogenaamde lookup table te accepteren. Het systeem werkt volledig naar behoren op dit moment en maakt gebruik van de in de lampen ingebouwde kleurtemperatuur naar rgb conversie.
De code staat hier onder. Het enige dat nog moet gebeuren om de eerste test te kunnen draaien is het vullen van de lookup tables.
De code v1.0
Sluiten
HueControl
HueControl
// V1.0 as of 08-03-2017
import processing.net.*;
import controlP5.*;
boolean connect = true; //is the Hue bridge available? (manual selector)
int[] lightArr = {1, 2, 3}; //the light #'s you want to control
String[] colorVars = {"ct", "bri"}; //the light variable names
int mainDelay = 50; //global delay length
public int minPerDataPoint = 5;
int transitiontime = (minPerDataPoint * 60); // in seconds
//int transitiontime = 4; // in seconds
ControlP5 cp5;
Client c;
int[] timeCode = {0,0}; // timecode, update?
int[] vals = new int[colorVars.length];
int[] previous = new int[colorVars.length];
//Lookup tables
String[] events;
int[] intensity;
int[] colorTemp;
void setup() {
size(200, 400);
//Initialise lookup tables
intensity = defineLookupTableBri();
colorTemp = defineLookupTableCt();
events = new String[colorTemp.length];
events[238] = "{\"alert\":\"select\"}";
GUIsetup();
}
void draw() {
timeCode = updateCheck(minPerDataPoint, timeCode);
delay(mainDelay);
}
Comm
Comm
String apiKey = "###";
String ip = "192.168.1.69";
int ipPort = 80;
// Function updates scene with String input & without update required check
void sceneUpdate(int[] lamps, String val) {
int[] empty = {};
if (val.length() > 0 && connect) {
for (int i=0; i<lamps.length; i++) {
sendToLamp(lamps[i], empty, val);
}
}
}
// Function updates scene with int array input & update required check
int[] sceneUpdate(int[] lamps, int[] prev, int[] val) {
// If input is a integer array
if (val.length > 0) {
boolean update = false;
// See if lights should be updated
for (int i=0; i < val.length; i++) {
if (val[i] != prev[i]) {
update = true;
}
}
// If lights should be updated do this
if (update && connect) {
// Send data to every lamp in scene
for (int i=0; i<lamps.length; i++) {
sendToLamp(lamps[i], val);
}
return val;
}
}
return prev;
}
void sendToLamp(int lamp, int[] v) {
sendToLamp(lamp, v, "");
}
void sendToLamp(int lamp, int[] v, String special) {
c = new Client(this, ip, ipPort); // Connect to server
c.write("PUT /api/" + apiKey +"/lights/" + lamp + "/state HTTP/1.1\r\n");
String body;
if (special.length() > 0) {
body = special;
}
else {
body = "{";
for (int i=0; i < colorVars.length; i++) {
body += "\""+ colorVars[i] +"\":"+ v[i];
if (i != (colorVars.length-1)) {
body += ",";
}
}
body += ",\"transitiontime\":"+ (transitiontime*10);
body += "}";
}
c.write("Content-Length: "+ body.length() + "\r\n\r\n");
c.write(body+"\r\n");
println(body);
c.stop();
delay(50);
}
GUI
GUI
// Function runs in setup()
void GUIsetup() {
int butH = 40;
int marginTop = 25;
int marginBot = 2;
background(50);
noStroke();
cp5 = new ControlP5(this);
cp5.addButton("Lamps_On")
.setValue(1)
.setPosition(0, marginTop )
.setSize((width/2)-(marginBot/2), butH)
;
cp5.addButton("Lamps_Off")
.setPosition((width/2)+(marginBot/2), marginTop )
.setSize(width/2,butH)
;
cp5.addButton("Blink")
.setPosition(0, (marginTop + butH + marginBot) )
.setSize(width,butH)
;
cp5.addButton("Blink_Long")
.setPosition(0, (marginTop + butH*2 + marginBot*2) )
.setSize(width,butH)
;
cp5.addButton("ColorCycle_Start")
.setPosition(0, (marginTop + butH*3 + marginBot*3) )
.setSize((width/2)-(marginBot/2), butH)
;
cp5.addButton("ColorCycle_Stop")
.setValue(1)
.setPosition((width/2)+(marginBot/2), (marginTop + butH*3 + marginBot*3) )
.setSize(width/2,butH)
;
}
void GUIupdate(int[] vals, int tCode) {
if (connect) fill(0,255,0);
else fill(255,0,0);
ellipse(10, 12, 10, 10);
String txt = "";
for (int i=0; i<colorVars.length; i++) {
txt += colorVars[i] +": "+ vals[i] +" ";
}
fill(255);
textSize(10);
text(txt, 20, 16);
text("Timecode: "+tCode, 3, height-3);
}
public void Lamps_On() {
println("Turn on lamps");
sceneUpdate(lightArr, "{\"on\":true}");
}
public void Lamps_Off() {
println("Turn off lamps");
sceneUpdate(lightArr, "{\"on\":false}");
}
public void Blink() {
println("Blink lamps");
sceneUpdate(lightArr, "{\"alert\":\"select\"}");
}
public void Blink_Long() {
println("Blink lamps long");
sceneUpdate(lightArr, "{\"alert\":\"lselect\"}");
}
public void ColorCycle_Start() {
println("Cycle lamps effect start");
sceneUpdate(lightArr, "{\"effect\":\"colorloop\"}");
}
public void ColorCycle_Stop() {
println("Cycle lamps effect stop");
sceneUpdate(lightArr, "{\"effect\":\"none\"}");
}
Lookup
Lookup
//Filled with temporary data
int[] defineLookupTableBri() {
int[] bri = {
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,
254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,
254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254
};
return bri;
}
//Filled with temporary data
int[] defineLookupTableCt() {
int[] ct = {
0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164,166,168,170,172,174,176,178,180,182,184,186,188,190,192,194,196,198,200,202,204,206,208,210,212,214,216,218,220,222,224,226,228,230,232,234,236,238,240,242,244,246,248,250,252,254,256,258,260,262,264,266,268,270,272,274,276,278,280,282,284,286,288,290,292,294,296,298,300,302,304,306,308,310,312,314,316,318,320,322,324,326,328,330,332,334,336,338,340,342,344,346,348,350,352,354,356,358,360,362,364,366,368,370,372,374,376,378,380,382,384,386,388,390,392,394,396,398,400,402,404,406,408,410,412,414,416,418,420,422,424,426,428,430,432,434,436,438,440,442,444,446,448,450,452,454,456,458,460,462,464,466,468,470,472,474,476,478,480,482,484,486,488,490,492,494,496,498,
500,500,500,500,500,500,500,500,500,500,500,500,500,500,500,500,500,500,500,
500,500,500,500,500,500,500,500,500,500,500,500,500,500,500,500,500,500,500
};
return ct;
}
/*
//File to make empty lookup tables
int h = 24;
int m = 60;
int minPerDataPoint = 5;
int dataPoints = (h*m) / minPerDataPoint;
int[] arr = new int[dataPoints];
String out = "";
void setup() {
for(int i=0; i<dataPoints; i+=1) {
arr[i] = 0;
out += ","+i*2;
}
}
void draw() {
println(arr);
println(out);
exit();
}
*/
Update
Update
int[] updateCheck(int interval, int[] prev) {
int minPHour = 60;
int newCode = floor( ( (hour()*minPHour) + minute() ) / interval );
if ( prev[0] != newCode ) {
prev[0] = newCode;
println("Timecode: "+prev[0]);
prev[1] = 1;
update(newCode);
} else {
prev[1] = 0;
}
return prev;
}
void update(int tCode) {
println("update");
int[] vals = { colorTemp[ tCode ], intensity[ tCode ] };
//println(vals);
previous = sceneUpdate(lightArr, previous, vals);
if (events[ tCode ] != null) {
println("event");
sceneUpdate(lightArr, events[tCode]);
}
GUIupdate(vals, tCode);
}
Update: Good morning, sunshine
Ik ben—misschien iets te—actief bezig geweest met de ontwikkeling van het controle programma. Het werkt nu een stuk eleganter en het is een stuk bruikbaarder voor een daadwerkelijke gebruiker. Dit heb ik deels gedaan omdat ik dat zelf fijn vind, maar ook met het oog op fase 2.
Ondertussen gebruik ik het systeem ongeveer een week en ik ben er erg blij mee. De datastroom moet nog beter geoptimaliseerd worden, maar het is enorm fijn wakker worden en ik heb het een stuk makkelijker met wakker worden. Ook op tijd naar bed gaan is makkelijker geworden. Al met al ben ik erg enthousiast. Ik ben zo enthousiast dat ik zo snel mogelijk van anderen wil horen hoe het hun bevalt in fase 2. Al zie ik er wel een beetje tegen op om mijn lampen af te staan.
Fase 2: User testing
Ik ben maar een enkel persoon en mijn woord is geen wet. Daarom is het belangrijk om anderen mijn systeem te laten testen. Vanwege gelimiteerde hardware wil ik met met slechts minimaal 3 mensen testen over een periode van 12 nachten. Voor deze test installeer ik de Hue lampen in hun slaapkamer en laat ik ze 4 nachten in het strakke ritme van de lampen leven. De overige 8 nachten wil ik besteden aan een nulmeting en de effecten achteraf. Data verzameling wil ik doen doormiddel van het bijhouden van een slaap dagboek en interviews.
Testperiode
Ik heb gekozen voor een periode van 4 nachten, omdat ik ik zo snel met meerdere gebruikers kan testen. Ik wil deze periode niet te lang maken, omdat het dan te lang zou duren voor de resultaten binnen zijn. Ik kan eventueel een fase 3 toevoegen als een langere periode nodig blijkt.
Voor het test wil ik drie keer deze periode aanhouden:
1 periode voor de interventie
sluiten
1 periode voor de interventie
Hiermee hoop ik een nulmeting te maken van het slaap-waak ritme van de testpersoon.
Om dit te loggen laat ik de testgebruikers een slaap dagboek bijhouden.
Omdat het hier om een nulmeting gaat zal ik geen enkele kennis delen met betrekking tot slapen.
Na deze periode vraag ik de tester het intake formulier in te vullen.
1 periode van interventie
sluiten
1 periode van interventie
In deze periode zijn de lampen daadwerkelijk geïnstalleerd en forceren ze als het ware de gebruiker om een regelmatig slaap-waak ritme aan te houden.
Ook hier maak ik weer gebruik van een slaap dagboek om het effect bij te houden. Na afloop van de periode zal ik ook een kort interview houden met de testgebruiker om een beeld te krijgen van de emotionele impact.
1 periode na de interventie
sluiten
1 periode na de interventie
Door ook na afloop van de interventie data te verzamelen hoop ik een beeld te krijgen van hoe fijn de gebruiker de interventie echt vond nu het er niet meer is. Ook wil ik kijken of ik kan zien of ze weer snel vervallen in hun patroon van voor de interventie.
Wederom zal ik de testgebruiker vragen om een slaap dagboek bij te houden en ik zal ook aan het eind van deze periode een kort interview houden om een beeld te krijgen van de emotionele impact.
Slaap dagboek
Dit is een beproefde methode in slaaponderzoek om een beeld te krijgen van het slaap-waak ritme en eventuele verstoringen. Ik gebruik hiervoor een standaard format.
Dit dagboek laat ik bijhouden met behulp van Google Forms. Dit doe ik zodat de testgebruiker kan kiezen of hij het invult op telefoon, tablet of pc.
Testgebruikers
Alleen al het vertellen waar ik mee bezig ben blijkt genoeg om testgebruikers te werven. Ik heb—zonder het actief te vragen—al van 3 medestudenten gehoord dat zij mij graag willen helpen met testen. Deze mensen zijn ook onderdeel van de beoogde doelgroep en zijn daarmee goede testgebruikers.
Ik wil nog wel kijken of ik ook een testgebruiker kan vinden die niet CMD studeert met het oog op diversiteit van de testgroep.
Ik wil met minimaal 3 gebruikers testen.
Technische uitvoering
Mijn controller app heb ik geschreven in Processing wat betekend dat ik een computer nodig heb om het te draaien. Vanwege de beveiliging van de Hue API moet dit een computer zijn die op hetzelfde netwerk zit als de Hue Bridge.
Om dit te realiseren ga ik een Raspberry Pi gebruiken. Dit is een mini computer die het besturingsysteem Raspbian (Linux-based) draait. Processing is ook beschikbaar voor dit systeem.
Door een directe LAN-verbinding tussen de Pi en de Bridge hoop ik zelfs het gebruik van het WiFi netwerk te omzeilen. Dit zou de setup super simpel moeten maken en de betrouwbaarheid moeten verbeteren.
Ik heb echter nog nooit met een Raspberry Pi gewerkt, maar ik verwacht weinig problemen. De Pi heb ik ondertussen besteld. Alternatief is het gebruik van een Mac mini welke ik van school kan lenen.
Update
De Pi is binnen en heb hem in gebruik genomen. Er waren inderdaad geen problemen. Ik hoopte de Hue bridge direct op de Pi aan te kunnen sluiten met een LAN-kabel. Dit lukte echter niet, omdat ik het actieve IP adres niet kon vinden. Ik heb dit opgelost door een WiFi repeater er tussen te plaatsen.
Van links naar rechts: Raspberry Pi, WiFi repeater, Hue Bridge en Hue lamp waarbij de Pi de commando's formuleert.
Deze setup werkt zonder enige afhankelijkheid van een bestaand lokaal netwerk, waardoor ik het overal waar ik stroom heb kan gebruiken. Hierdoor is het simpel om het systeem op te zetten voor gebruikerstests.
Update
Het is mij gelukt om de WiFi repeater er tussenuit te halen. Dit maakt het nog simpeler in opzet. De Raspberry Pi is nu direct verbonden met de Hue Bridge via een LAN kabel.
Fase 2: Sidestep
Ik ben in de gelukkige situatie terecht gekomen dat ik kan testen bij iemand die zijn hele huis vol heeft hangen met Philips Hue. Deze test ga ik iets anders aanpakken, omdat deze vooral focust op probleemherkenning en -oplossing wanneer het hele huis op hetzelfde ritme zit.
Ik ben van plan om dagelijks even contact op te nemen met de tester, om zo een beeld te krijgen van de problemen waar hij tegenaan loopt.
Technische uitvoering
Om er voor te zorgen dat ik het systeem van de tester niet verstoor bedien ik de lampen dit keer via WiFi vanaf een Raspberry Pi 3 model B. Op deze manier blijven alle huidige bedien methodes intact. Mijn controller werkt als een extra bedieningslaag.
Dat betekend ook dat ik geen extra informatie kan sturen als de lampen aangezet worden. Ik heb daarom de code zo aangepast dat hij elke 5 minuten een update stuurt, ook als de waardes hetzelfde blijven. Dit is geen perfecte, maar wel een snelle oplossing.
Als ik bij de tester ben hoef ik alleen nog het volgende te doen:
- Verbinden met WiFi netwerk
- API key krijgen van bridge
- Slaap- en waaktijden aanpassen
- Eventueel andere instellingen aanpassen