Brainstorming

Our first idea was to keep the idea of a lamp, but we had to remake the story in order to use more sensors. We also had to decide what sensors we wanted to use, so that way we could adapt our story to the sensor we were using. We knew that with the knowledge we had and with a little bit of help, we could use:

The next step was to determine the design of the lamp, and for this we also had to establish the possible user. We decided that kids on ages 6-10 would be our perfect user. Because of this, we made a mood-board to brainstorm a possible design. 

As our lamp is supposed to be used by little kids, we wanted it to be the most interactive, fun and attractive. We opted for a book design with a fun cutout on the cover that had to do with the story, this way the little kids could imagine the story more and have fun while using the lamp as it would be 100% interactive. 

Story & Design

After deciding the types of sensors we wanted to use, we had to create a story. We parted by the fact that it had to be a children's story and that the story had to have different outcomes along the story line, in which each outcome had to make the listener choose between two options. The main idea of the project is that the user has to interact with the book either making a sound, shaking the book, blowing to it , etc. for the story to continue in the direction they want.

We created a story with 14 different outcomes, in which the user had to have different interactions with the book to keep the story going, all depending on what they choose.

For the cover of the book, we decided to make it fun and easy to understand for the users. The main idea of the story it has to do with a balloon, so the cover has a big balloon cutout in it. Also, we decided to decorate the cover with different symbols were the sensors are placed, so the user knows where exactly they have to interact with the book when it comes to the different decision making along the story.

Here the code of our project, the different elements of our code work individually but once assembled the code no longer works :

// ** Librairies **
#include <Wire.h>

#include "SoftwareSerial.h"
#include "DFPlayer_Mini_Mp3.h"
#include "DHT.h"
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
 #include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif

// Which pin on the Arduino is connected to the NeoPixels?
// On a Trinket or Gemma we suggest changing this to 1:
#define LED_PIN    6
#define LED_COUNT 56

// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
// Argument 1 = Number of pixels in NeoPixel strip

#define DHTPIN 12
#define DHTTYPE DHT11

DHT dht(DHTPIN, DHTTYPE);

// ** Pins **
int micPin = A3;      // Big sound sensor
int tempPin = A4;     // Temperature sensor
int buttonPin = 5;    // Tilt sensor
int SENSOR_PIN = 8;   // Touch sensor

// Le capteur de pression a deux sorties : A4 et A5.

// ** Variables **
int currentState;
int lastState = LOW;
int val;
float tempValue;
float voltageOut;
float temperatureC;
float sensorValue2;
float voltageOut2;
float temperatureC2;
int micValue1 = 0;
int micValue2 = 0;

int blowValue1 = 0;
int blowValue2 = 0;

SoftwareSerial mySerial(10, 11); // RX, TX

// ** Conditions **
bool touchActivated = false;
bool motionActivated = false;
bool bigActivated = false;
bool smallActivated = false;
bool tempActivated = false;

bool tempChanged = false;
bool bigChanged = false;
bool smallChanged = false;
bool touchChanged = false;
bool motionChanged = false;

void setup() {
  #if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
  clock_prescale_set(clock_div_1);
#endif
  mySerial.begin(9600);
  Serial.begin(9600);
  mp3_set_serial(mySerial);
  mp3_set_volume(15);
  mp3_set_EQ(0);
  

  Serial.println(F("DHT11 test!"));

  dht.begin();

  // Touch sensor :
  pinMode(SENSOR_PIN, INPUT);

  // Motion sensor :
  pinMode(buttonPin, INPUT);

  // Temp sensor :
  pinMode(tempPin, INPUT);

  // Big-sound sensor :
  pinMode(micPin, INPUT);

  introduction();
}

void loop() {

  // Partie premier choix : toucher et inclinaison

  bool choiceMade = false;
  
  unsigned long startTime = millis();
  while (millis() - startTime < 10000 && !choiceMade) {
    touchActivated = touchCheck();
    motionActivated = motionCheck();

    if (touchActivated) {
      Serial.println("Choix : Capteur de toucher activé !");
      choiceMade = true;
    } else if (motionActivated) {
      Serial.println("Choix : Capteur d'inclinaison activé !");
      choiceMade = true;
    }
  }
  
  if (!choiceMade) {
    Serial.println("Vous n'avez pas fait de choix !");
  } else if (touchActivated){
      touchActivated = false;
      Choice1A();
  } else if (motionActivated){
      motionActivated = false;
      Choice1B();
  }

  // Attendre un court laps de temps avant de recommencer
  // delay(1000);
}

void introduction() {
  Serial.println("Bienvenue dans l'histoire interactive !");

  mp3_play(1);
      
      colorWipe(strip.Color(255,   0,   127), 50);  
      delay(5000); 
      colorWipe(strip.Color(249,  66,   158), 50); //Rose 
      delay(5000);
      colorWipe(strip.Color(255,   0,   127), 50); 
      delay(5000); 
      colorWipe(strip.Color(249,  66,   158), 50); //Rose 
      delay(10000);
      colorWipe(strip.Color(0,   127,   255), 50);  //bleu
      delay(5000);
      colorWipe(strip.Color(0,   191,   255), 50);
      delay(4000);  
      colorWipe(strip.Color(0,   127,   255), 50);  //bleu
      delay(4000);
      colorWipe(strip.Color(0,   191,   255), 50);
      delay(4000);  
      colorWipe(strip.Color(0,   127,   255), 50);  //bleu
      
      delay(4000);  
      theaterChase(strip.Color(127, 127, 127), 50); 
      theaterChase(strip.Color(127, 127, 127), 50); 
      theaterChase(strip.Color(127, 127, 127), 50); 
      theaterChase(strip.Color(127, 127, 127), 50); 
      theaterChase(strip.Color(127, 127, 127), 50); 
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);

    
     


}

void Choice1A(){

  Serial.println("On est bien rentrés sur la voie 1A !");

  mp3_play(2);
      colorWipe(strip.Color(255,   0,   0), 50);
      delay(18000);
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      
      

  bool choiceMade = false;
  
  unsigned long startTime = millis();
  while (millis() - startTime < 10000 && !choiceMade) {
    touchActivated = touchCheck();
    motionActivated = motionCheck();

    if (touchActivated) {
      Serial.println("Choix : Capteur de toucher activé !");
      choiceMade = true;
    } else if (motionActivated) {
      Serial.println("Choix : Capteur d'inclinaison activé !");
      choiceMade = true;
    }
  }
  
  if (!choiceMade) {
    Serial.println("Vous n'avez pas fait de choix !");
  } else if (touchActivated){
      touchActivated = false;
      Choice2A();
  } else if (motionActivated){
      motionActivated = false;
      Choice2B();
  }

}

void Choice1B(){

  Serial.println("On est bien rentrés sur la voie 1B !");

  // Ajouter code pour le ruban LED et audio ici :
  // Code ruban LED
  // mp3_play(1); // Joue l'audio 0001.mp3 du dossier mp3 de la carte SD

  // Partie choix 1B : son et inclinaison
  mp3_play(9);
      colorWipe(strip.Color(0,   25,   30), 50);  
      delay(11000); 
      
       colorWipe(strip.Color(0,   0,   255), 50); 
      delay(7000);  
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
       theaterChase(strip.Color(127,   127,   127), 50);

  bool choiceMade = false;
  
  unsigned long startTime = millis();
  while (millis() - startTime < 10000 && !choiceMade) {
    bigActivated = bigCheck();
    motionActivated = motionCheck();

    if (bigActivated) {
      Serial.println("Choix : Capteur de son activé !");
      choiceMade = true;
    } else if (motionActivated) {
      Serial.println("Choix : Capteur d'inclinaison activé !");
      choiceMade = true;
    }
  }
  
  if (!choiceMade) {
    Serial.println("Vous n'avez pas fait de choix !");
  } else if (bigActivated){
      bigActivated = false;
      Choice2C();
  } else if (motionActivated){
      motionActivated = false;
      Choice2D();
  }

}

void Choice2A(){

  Serial.println("On est bien rentrés sur la voie 2A !");

mp3_play(3);
       rainbow(20);     
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      theaterChase(strip.Color(127, 127, 127), 50);
      
      

  bool choiceMade = false;
  
  unsigned long startTime = millis();
  while (millis() - startTime < 10000 && !choiceMade) {
    bigActivated = bigCheck();
    tempActivated = tempCheck();

    if (bigActivated) {
      Serial.println("Choix : Capteur de souffle activé !");
      choiceMade = true;
    } else if (tempActivated) {
      Serial.println("Choix : Capteur de température activé !");
      choiceMade = true;
    }
  }
  
  if (!choiceMade) {
    Serial.println("Vous n'avez pas fait de choix !");
  } else if (bigActivated){
      bigActivated = false;
      Choice3A();
  } else if (tempActivated){
      tempActivated = false;
      Choice3B();
  }

}

void Choice2B(){

  Serial.println("On est bien rentrés sur la voie 2B !");

  // Ajouter code pour le ruban LED et audio ici :
  // Code ruban LED
  // mp3_play(1); // Joue l'audio 0001.mp3 du dossier mp3 de la carte SD

  // Partie choix 2B : température et son
  mp3_play(6);
       colorWipe(strip.Color(255,   20,   0 ), 90); 
       delay(5000);
       theaterChase(strip.Color(255,   20,   0), 50);
       colorWipe(strip.Color(226,   51,   0), 50);
       delay(5000);
       
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);


  bool choiceMade = false;
  
  unsigned long startTime = millis();
  while (millis() - startTime < 10000 && !choiceMade) {
    tempActivated = tempCheck();
    bigActivated = bigCheck();

    if (bigActivated) {
      Serial.println("Choix : Capteur de son activé !");
      choiceMade = true;
    } else if (tempActivated) {
      Serial.println("Choix : Capteur de température activé !");
      choiceMade = true;
    }
  }
  
  if (!choiceMade) {
    Serial.println("Vous n'avez pas fait de choix !");
  } else if (bigActivated){
      bigActivated = false;
      Choice3D();
  } else if (tempActivated){
      tempActivated = false;
      Choice3C();
  }

}

void Choice2C(){

  Serial.println("On est bien rentrés sur la voie 2C !");

  // Ajouter code pour le ruban LED et audio ici :
  // Code ruban LED
  // mp3_play(1); // Joue l'audio 0001.mp3 du dossier mp3 de la carte SD

  // Partie choix 2C : souffle et température
      mp3_play(10);
      colorWipe(strip.Color(255,   150,   0), 50);  
      delay(23000); 
      theaterChase(strip.Color(255,   150,   0), 50);
      colorWipe(strip.Color(255,   150,   0), 50); 
      delay(11000); 

      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);

  bool choiceMade = false;
  
  unsigned long startTime = millis();
  while (millis() - startTime < 10000 && !choiceMade) {
    bigActivated = bigCheck();
    tempActivated = tempCheck();

    if (bigActivated) {
      Serial.println("Choix : Capteur de souffle activé !");
      choiceMade = true;
    } else if (tempActivated) {
      Serial.println("Choix : Capteur de température activé !");
      choiceMade = true;
    }
  }
  
  if (!choiceMade) {
    Serial.println("Vous n'avez pas fait de choix !");
  } else if (bigActivated){
      bigActivated = false;
      Choice3F();
  } else if (tempActivated){
      tempActivated = false;
      Choice3E();
  }


}

void Choice2D(){

  Serial.println("On est bien rentrés sur la voie 2D !");

  // Ajouter code pour le ruban LED et audio ici :
  // Code ruban LED
  // mp3_play(1); // Joue l'audio 0001.mp3 du dossier mp3 de la carte SD

  // Partie choix 2D : souffle et inclinaison
   mp3_play(13);
      colorWipe(strip.Color(0,   200,   20), 50); // Red
      delay(12000);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      theaterChase(strip.Color(127,   127,   127), 50);
      

  bool choiceMade = false;
  
  unsigned long startTime = millis();
  while (millis() - startTime < 10000 && !choiceMade) {
    bigActivated = bigCheck();
    motionActivated = motionCheck();

    if (bigActivated) {
      Serial.println("Choix : Capteur de souffle activé !");
      choiceMade = true;
    } else if (motionActivated) {
      Serial.println("Choix : Capteur d'inclinaison activé !");
      choiceMade = true;
    }
  }
  
  if (!choiceMade) {
    Serial.println("Vous n'avez pas fait de choix !");
  } else if (bigActivated){
      bigActivated = false;
      Choice3G();
  } else if (motionActivated){
      motionActivated = false;
      Choice3H();
  }

}

void Choice3A(){

  Serial.println("On est bien rentrés sur la voie 3A !");

  // Ajouter code pour le ruban LED et audio ici :
  // Code ruban LED
  // mp3_play(1); // Joue l'audio 0001.mp3 du dossier mp3 de la carte SD
  mp3_play(4);
      theaterChase(strip.Color(255,   0,   127), 50);
      theaterChase(strip.Color(255,   0,   127), 50);
      theaterChase(strip.Color(255,   0,   127), 50);
     theaterChase(strip.Color(255,   0,   127), 50);
      theaterChase(strip.Color(255,   0,   127), 50);
      theaterChase(strip.Color(255,   0,   127), 50);
      theaterChase(strip.Color(255,   0,   127), 50);
    rainbow(3);

}

void Choice3B(){

  Serial.println("On est bien rentrés sur la voie 3B !");

  // Ajouter code pour le ruban LED et audio ici :
  // Code ruban LED
  // mp3_play(1); // Joue l'audio 0001.mp3 du dossier mp3 de la carte SD
  mp3_play(5);
       colorWipe(strip.Color(255,   0,   0), 50); // Red
       delay(11000);
       colorWipe(strip.Color(255,   100,   5 ), 50); 
       delay(30000);

}

void Choice3C(){

  Serial.println("On est bien rentrés sur la voie 3C !");

  // Ajouter code pour le ruban LED et audio ici :
  // Code ruban LED
  // mp3_play(1); // Joue l'audio 0001.mp3 du dossier mp3 de la carte SD
  mp3_play(7);
       colorWipe(strip.Color(0,   0,   255 ), 90); 

}

void Choice3D(){

  Serial.println("On est bien rentrés sur la voie 3D !");

  // Ajouter code pour le ruban LED et audio ici :
  // Code ruban LED
  // mp3_play(1); // Joue l'audio 0001.mp3 du dossier mp3 de la carte SD
  mp3_play(8);
      colorWipe(strip.Color(255,   0,   127), 50);  
      delay(10000); 
       theaterChase(strip.Color(249,  66,   158), 50);
        theaterChase(strip.Color(249,  66,   158), 50);
       colorWipe(strip.Color(255,   100,   5), 50);  

}

void Choice3E(){

  Serial.println("On est bien rentrés sur la voie 3E !");

  // Ajouter code pour le ruban LED et audio ici :
  // Code ruban LED
  // mp3_play(1); // Joue l'audio 0001.mp3 du dossier mp3 de la carte SD
  mp3_play(11);
      colorWipe(strip.Color(0,   50,   100), 50);  
      delay(6000); 

      colorWipe(strip.Color(249,  66,   158), 50); 

}

void Choice3F(){

  Serial.println("On est bien rentrés sur la voie 3F !");

  // Ajouter code pour le ruban LED et audio ici :
  // Code ruban LED
  // mp3_play(1); // Joue l'audio 0001.mp3 du dossier mp3 de la carte SD
  mp3_play(12);
      colorWipe(strip.Color(255,   0,   0), 50); // Red
      delay(8000);
      colorWipe(strip.Color(0,   0,   255), 50); // Red

}

void Choice3G(){

  Serial.println("On est bien rentrés sur la voie 3G !");

  // Ajouter code pour le ruban LED et audio ici :
  // Code ruban LED
  // mp3_play(1); // Joue l'audio 0001.mp3 du dossier mp3 de la carte SD
  mp3_play(14);
     
      colorWipe(strip.Color(0,   200,   200), 50); // Red
      delay(10000);
      colorWipe(strip.Color(200,   100,   50), 50);

}

void Choice3H(){

  Serial.println("On est bien rentrés sur la voie 3H !");

  // Ajouter code pour le ruban LED et audio ici :
  // Code ruban LED
  // mp3_play(1); // Joue l'audio 0001.mp3 du dossier mp3 de la carte SD
  mp3_play(15);
     
      colorWipe(strip.Color(250,   0,   20), 50); // Red
      delay(16000);
      rainbow(10);

}

bool motionCheck() {
  motionChanged = false;
  val = digitalRead(buttonPin);
  
  if (val == LOW) {
    motionChanged = true;
  }
  
  return motionChanged;
}

bool touchCheck() {
  currentState = digitalRead(SENSOR_PIN);
  
  if (lastState == LOW && currentState == HIGH) {
    touchChanged = true;
  } else {
    touchChanged = false;
  }
  
  lastState = currentState;
  return touchChanged;
}

bool bigCheck() {
  bigChanged = false;
  
  micValue1 = analogRead(micPin);
  micValue1 = constrain(micValue1, 0, 100);

  delay(1000);

  micValue2 = analogRead(micPin);
  micValue2 = constrain(micValue2, 0, 100);

  if ((micValue2 - micValue1 > 27) || (micValue1 - micValue2 > 27)) {
    bigChanged = true;
  }

  return bigChanged;
}

bool tempCheck() {
  tempChanged = false;

  tempValue = dht.readTemperature();
  //voltageOut = (tempValue * 5000) / 1024;
  //temperatureC = voltageOut / 10;

  delay(3000);

  sensorValue2 = dht.readTemperature();
  //voltageOut2 = (sensorValue2 * 5000) / 1024;
  //temperatureC2 = voltageOut2 / 10;

  if ((sensorValue2 - tempValue) > 0) {
    tempChanged = true;
  }

  return tempChanged;
}

void colorWipe(uint32_t color, int wait) {
  for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
    strip.setPixelColor(i, color);         //  Set pixel's color (in RAM)
    strip.show();                          //  Update strip to match
    delay(wait);                           //  Pause for a moment
  }
}

// Theater-marquee-style chasing lights. Pass in a color (32-bit value,
// a la strip.Color(r,g,b) as mentioned above), and a delay time (in ms)
// between frames.
void theaterChase(uint32_t color, int wait) {
  for(int a=0; a<10; a++) {  // Repeat 10 times...
    for(int b=0; b<3; b++) { //  'b' counts from 0 to 2...
      strip.clear();         //   Set all pixels in RAM to 0 (off)
      // 'c' counts up from 'b' to end of strip in steps of 3...
      for(int c=b; c<strip.numPixels(); c += 3) {
        strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
      }
      strip.show(); // Update strip with new contents
      delay(wait);  // Pause for a moment
    }
  }
}

// Rainbow cycle along whole strip. Pass delay time (in ms) between frames.
void rainbow(int wait) {
  // Hue of first pixel runs 5 complete loops through the color wheel.
  // Color wheel has a range of 65536 but it's OK if we roll over, so
  // just count from 0 to 5*65536. Adding 256 to firstPixelHue each time
  // means we'll make 5*65536/256 = 1280 passes through this loop:
  for(long firstPixelHue = 0; firstPixelHue < 5*65536; firstPixelHue += 256) {
    // strip.rainbow() can take a single argument (first pixel hue) or
    // optionally a few extras: number of rainbow repetitions (default 1),
    // saturation and value (brightness) (both 0-255, similar to the
    // ColorHSV() function, default 255), and a true/false flag for whether
    // to apply gamma correction to provide 'truer' colors (default true).
    strip.rainbow(firstPixelHue);
    // Above line is equivalent to:
    // strip.rainbow(firstPixelHue, 1, 255, 255, true);
    strip.show(); // Update strip with new contents
    delay(wait);  // Pause for a moment
  }
}

// Rainbow-enhanced theater marquee. Pass delay time (in ms) between frames.
void theaterChaseRainbow(int wait) {
  int firstPixelHue = 0;     // First pixel starts at red (hue 0)
  for(int a=0; a<30; a++) {  // Repeat 30 times...
    for(int b=0; b<3; b++) { //  'b' counts from 0 to 2...
      strip.clear();         //   Set all pixels in RAM to 0 (off)
      // 'c' counts up from 'b' to end of strip in increments of 3...
      for(int c=b; c<strip.numPixels(); c += 3) {
        // hue of pixel 'c' is offset by an amount to make one full
        // revolution of the color wheel (range 65536) along the length
        // of the strip (strip.numPixels() steps):
        int      hue   = firstPixelHue + c * 65536L / strip.numPixels();
        uint32_t color = strip.gamma32(strip.ColorHSV(hue)); // hue -> RGB
        strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
      }
      strip.show();                // Update strip with new contents
      delay(wait);                 // Pause for a moment
      firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames
    }
  }
}