mercoledì 2 aprile 2014

Banana touch: un light controller per le Philips Hue - parte 2: comandare la lampada

Per controllare la lampada ho utilizzato la porta Ethernet del mio Arduino Ethernet, per collegarlo al Bridge delle Philips Hue. Il tutto attraverso un piccolo router che mi fungeva in questo caso da switch e da server dhcp.
Per maggiori dettagli di come vengono inviati i comandi alle Philips Hue tornate ai miei post precedenti sull'argomento.

Per inviare il codice colore e la luminosità ho predisposto una funzione chiamata setHue(X,Y,B) dove X e Y rappresentano i codice colore 0-255 e B la luminosità sempre in range 0-255.



void httpRequest(String hueCmd) {

  Serial.println(hueCmd);
 
  Serial.println("httpRequest...");
  if (client.connect(ipAddressHue, 80)) 
  {
    if (client.connected())
    {
     Serial.println("connecting...");
     client.print("PUT /api/");
     client.print(hueUsername);
     client.print("/lights/");
     client.print(hueLight + 1);  // hueLight zero based, add 1
     client.println("/state HTTP/1.1");
     client.println("keep-alive");
     client.print("Host: ");
     client.println(hueHubIP);
     client.print("Content-Length: ");
     client.println(hueCmd.length());
     client.println("Content-Type: text/plain;charset=UTF-8");
     client.println();  // blank line before body
     client.println(hueCmd);  // Hue command 
 
    }
    // close the connection
    client.stop();    
    Serial.println("disconnected");
  }
  else {
    Serial.println("connection failed");
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
  } 

}

double x,y;
char buf[32]; // needs to be at least large enough to fit the formatted text
char buf2[32]; // needs to be at least large enough to fit the formatted text
String hueCommand="";

void setHue(long X, long Y , long B)
{
  if (X+Y+B<120)
  {
    if (isOn=HIGH)
    {
      hueCommand="{ \"on\":false }";
      isOn=LOW;
    }
  }
  else
  {
    x=(double)((double)X/(double)255);
    y=(double)((double)Y/(double)255);
    dtostrf(x,2,1,buf);
    dtostrf(y,2,1,buf2);
    hueCommand="{ \"on\":true, \"bri\":" + String(B) + " , \"xy\":[" + String(buf) +"," + buf2 +"] }";
    isOn=HIGH;
  }
  httpRequest(hueCommand);
}

La parte più interessante è sicuramente quello che sta a monte, ovvero la misurazione del tempo di carica. Il tutto è fatto cambiando rapidamente lo stato del pin e misurandone il tempo di carica, poi "normalizzato" come valore di distanza tramite radice quadrata (vedi post precedente). Le misurazioni avvengono a gruppi di 3, in modo poi da ottenere un valore medio, molto più stabile.
Le letture avvengono accedendo in modo diretto ai registri di arduino. (PINB e PIND).


 for (int i=0;i<3;i++)
  {
   normalizedA+= normalize(zeroA,getDistance(time(SENSOR_A  , B00000001)),1000);
   normalizedB+= normalize(zeroB,getDistance(time(SENSOR_B  , B00000010)),500);
   normalizedC+= normalize(zeroC,getDistance(time(SENSOR_C  , B10000000)),500);
   normalizedD+= normalize(zeroD,getDistance(time(SENSOR_D  , B01000000)),500);
   normalizedE+= normalize(zeroE,getDistance(time(SENSOR_E  , B00100000)),500);
  }
  normalizedA=normalizedA/3;
  normalizedB=normalizedB/3;
  normalizedC=normalizedC/3;
  normalizedD=normalizedD/3;
  normalizedE=normalizedE/3;

long time(int pin, byte mask) {
  unsigned long count = 0, total = 0;
  while(checkTimer() < refresh) {
    // pinMode is about 6 times slower than assigning
    // DDRB directly, but that pause is important
    pinMode(pin, OUTPUT);
    PORTB = 0;
    PORTD = 0;
    pinMode(pin, INPUT);
    if (pin<=7 )
    {
    while((PIND & mask) == 0)
      count++;
    }
    else
    {
      while((PINB & mask) == 0)
      count++;

    }
    total++;
  }
  startTimer();
  return (count << resolution) / total;
}

long getDistance(long value)
{
 return  (long) ((double)1)/sqrt((double)(value/2))*1000000000;
}

long normalize(long zeroValue, long distanceValue, long scaleValue)
{
  long normalized=0;
  normalized=zeroValue - distanceValue ;
  if (normalized<0)  { normalized=0; };
  normalized=normalized/scaleValue;
  if (normalized>255) {normalized=255;};
  return normalized;
}

Scarica lo sketch completo




Nessun commento:

Posta un commento