Project tutorial

SMART CUBE: A New Way to Control Your Home © GPL3+

Discover a new way to interact with your smart home thanks to Arduino 101: tilt and shake the cube to control your devices via Bluetooth!

  • 10,487 views
  • 7 comments
  • 28 respects

Components and supplies

Necessary tools and machines

Lasercutter
Laser cutter (generic)
09507 01
Soldering iron (generic)

Apps and online services

About this project

What is SMART CUBE?

Smart Cube is a controller for your Smart Home devices.

Nowadays managing in a smarter way all the devices in our homes is becoming an exigence. We need something simple and intuitive to use. Smart Cube could be a solution: it’s a portable device that contains an Arduino 101 board and some sensors that communicate with the appliances and the actuators in your Smart Home.

The innovation of this remote controller is related with the innovation of Arduino 101 board. It uses Bluetooth (BLE) to control lights, temperature and your tv and you can also synchronize it with your smartphone. But the major innovation is the way you interact with Smart Cube with your gesture using the gyroscope and the accelerometer. The cube has 6 faces and each one control a particular function. The function you want to use is detected thanks to the gyroscope that recognize the upper face. For example you can open the lights of the room in which you are just by positioning the cube with the “light face” in the upper position. If you want to switch off the light you just need to shake the cube.

If a face is UP and it doesn’t move for more than 2 seconds it is activated the related function. This delay is made so that you can have the time to rotate and interact with the cube to find the face you need without activating accidentally other functions. When you shake the cube for more than 2 seconds, the last activated function is closed.

This project aims to help you to build a smart controller. This device need a receiver (smart centraline in the picture) that interpret the data and manage the functions of your smart home. The main output of the cube is a BLE signal that could be used in many ways: for example you can connect the cube with a smartphone app (or make your own), or you can build a station with another Arduino that collect the BLE data and directly controls the appliances of your home. Because of the variety of cases, this part depends on your exigence. In this guide we will see how to build a smart cube and you'll learn how to personalize it.

Functions:

The structure of the code is easy to personalize (we analyze the code later) so that you can decide which functions to control. These are the functions that I decided to control:

LIGHTS: This face in UP position open the lights of the room in which you are. If you shake the cube the lights switch off and a yellow led in this face is activated so you can find the cube in the darkness. The communication with your lamps is made by the BLE of the 101 board.

TEMPERATURE: This face UP activate (via BLE) the air conditioning if it’s hot or the heating if it’s cold. It detects the temperature using a thermal sensor and open a blue led if the conditioner is on (snow flake) or a red one if the heating is activated (sun).

TIMER: This face UP start a timer that you can see on the LCD display. There is a buzzer that work as an alarm when the countdown is finished. If you shake you stop the timer and you can see the remaining time. When the countdown ends the color of the LCD change from blue to red and the buzzer make three sounds.

TV: This face UP open the TV. The cube become a remote controller for your TV. There is a button panel with numbers that is activated only if this face is UP so to avoid accidental touches. The number you push is send via BLE to the central controller that is connected to your TV. Shaking the cube you close the TV.

SOUND: This face UP activate a led whose brightness is based on the noise level of the room. The noise is detected thanks to a sound sensor. If you shake the cube you close this function. (If you want you can activate your personal function clapping your hands).

OFF face: If you don't shake the cube this face is like a neutral position in which nothing is changed. If you want to close everything position the cube with the OFF face UP and shake it. This gesture is like the home button on you smartphone that you press if you want to exit quickly. There is a red led so that you can find the cube if it’s dark.

Differences from the concept:

The original plan was to use also IR communication to connect your TV directly to the cube. Because the Arduino 101 don't support (for now) the library that manage the IR signals I decided to send the information via BLE to a station that can manage this library (like Arduino UNO). Because of this problem I have removed the radio function (very similar to TV face), replacing it with a sound sensor face. This face could be used to recognize a loud noise (like hand clapping) to activate something. The biggest change is in the material of the cube. Initially I though to build it with a 3D printer but then I decided to use a laser cutter. In this way is easier to substitute a face if you want to change a function. For example you can remove the timer face and change it with a face that automatically fill your cat's bowl. Being modular you don't need to re-build the entire structure!

Let's build it:

Follow this instructions to build your own smart cube. We'll start from the hardware, assembling the electronics components first and then the laser cut body of the cube made of MDF. After this operation I'll explain how the code works and how you can personalize it. After you have uploaded the code on your Arduino 101 you can download the app to see the BLE output of the cube or connect it directly with your smart home!

Hardware - electronics:

Let's start form your Arduino 101. This is the fritzing scheme to follow:

Mount the Grove base shield on your board and start with the connections.

Keypad: you have to connect the wires in order to the pins: 10, 8, 7, 6, 5, 4, 2.

LED connections:

First of all we have to prepare the leds:

- connect the long leg of the led (anode) to a 220 ohm resistance and then to a red wire (this is the cable to connect to the pin)

- connect the short leg (cathode) to a white wire (this will go to the gnd)

- solder the parts and cover them with electrical tape

- connect all the white cables to a single white cable (this will go to the gnd) and solder them all together

Now connect the red wires to your Arduino: GREEN led to pin 9, YELLOW led to pin 11, RED led to pin 12, BLUE led to pin 13 and the last RED to pin A2.

Grove sensors:

Connect the grove sensors to the shield (see scheme on attachments).

Buzzer to D3, LCD RGB to I2C, Temperature sensor to A0, Sound sensor to A1.

Ok, now we have connected all the electric parts. Now you need the case.

Hardware - box

You can download the sketch of the cube to cut with laser. The red lines in the sketch are the symbols of the faces, just engrave them. The black lines should be cut. The internal dimension of the cube is 9 cm. The sketch is ok if you use a 3mm material, if you use a different thickness you should modify it (you can use this website: http://www.makercase.com/).

The material I choose is MDF (Medium Density Fiber) but you can use what you want.

Here are some pictures of the laser cut:

Now we have to assemble it.

I glued some pieces of cardboard to make thickness for the led. In this way they will be aligned with the surface.

Now we mount the keypad. Insert it in the hole and remove the adhesive film, then reconnect the pins.

Now the RGB LCD. This fit perfectly the hole.

Let's prepare the battery connector:

I have cut an old transformer plug and connected it to a battery clip. In this way we save space inside the box.

At this point thats what you should have:

Now you just need to connect the battery, upload the code and close the cube!

TIP: fix the board and the battery with the case so that when you shake the cube they will be stable.

Code

You can find the code in the attachments. Upload it in your board with the Arduino IDE (remember to update your software for Arduino 101 compatibility).

I have commented almost every line of the code to make it more understandable that I can. Don't be afraid of the 500+ lines, the structure it's not so complicate.

At the beginning there are the libraries and all the variables declaration.

In this part there is also the definition of BLE services and characteristic. I used Automation IO service. I used the Digital characteristic for lights and temperature (this use 2 bit , so 4 possible cases to codify) and the Analog for TV (to send all the codes of the keypad).

Then the setup. This pat is executed only one time at the beginning. Here we initialize the components as inputs or outputs and initialize the BLE and the gyro of the 101 board.

The main part is the loop. It is divided in four parts:

  • 2 The second part we activate a face only if it is in the up position for more than two seconds. We use the millis function to count the time. When the position change it memorize the millis value and if the orientation remain the same, after an interval (2 sec), we enter in an if-zone where the selected face became true (for the 4th part).
  • 3 The third part is activated only if the cube is shaked with a certain intensity and for more than 2 seconds. The last activated face function is closed and the face is set as false. If the face is false can't enter in the 4th part.
  • 4 The fourth part is only for true faces. Here there is the core of the functions of the smart cube. In this part are constantly executed only the faces that are true in loop.

You can modify the face functions with some modifications of the code. The main structure should be as described. You can change the part inside the if conditions of every face.

if (face2 == true) { // TEMPERATURE face  
 
//START CHANGING HERE
 
 digitalWrite (LEDOFF, LOW); // if this face is true the OFF face led is LOW  
 if (central.connected() == true) { // if the cube is BLE connected   
  // read temperature value  
  int val = analogRead(pinTemp); // get analog value  
  resistance=(float)(1023-val)*10000/val; // get resistance  
  temperature=1/(log(resistance/10000)/B+1/298.15)-273.15;  
  // calculate temperature  
  //conditions of activation  
  if (temperature > tooHot) { // activate air conditioning  
   digitalWrite(LEDhot, LOW); // close heating led  
   digitalWrite(LEDcold, HIGH); // open air conditioner led  
   termoChar.setValue(1); // set via BLE the condition 1 = cold on - hot off  
  }  
  if (temperature < tooCold) { // activate heating  
   digitalWrite(LEDhot, HIGH);  
   digitalWrite(LEDcold, LOW);  
   termoChar.setValue(2); // 2 = cold off - hot on    
  }  
  if (temperature > tooCold && temperature < tooHot) { 
   // ideal temperature: nothing is activated  
   digitalWrite(LEDhot, LOW);  
   digitalWrite(LEDcold, LOW);  
   termoChar.setValue(0); // 0 = cold off - hot off  
  }  
 }  
 
//END HERE
 
}

You have to code the "true" part (as in the previous code) and also the "false" part when the cube is shaked:

// TEMPERATURE deactivation  
if (lastFUNCTION == 2) { // TEMPERATURE face  
 
 //START CHANGING HERE
 
 // if a central is connected to peripheral:  
 if (central.connected() == true) {  
  digitalWrite(LEDhot, LOW); // close temperature red led   
  digitalWrite(LEDcold, LOW); // close temperature blue led  
  termoChar.setValue(0); // temperature BLE signal: 0 = cold off - hot off  
 
 //END HERE
 
 }  
Serial.println("TEMPERATURE false - CLOSE");  
face2 = false; // TEMPERATURE face became false  
}

Remember to set the face as false when you shake it.

App:

To see the cube BLE outputs you can download this app: nRF Connect

https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp&hl=it

When you open it, just search for devices and connect with "smartcubesketch". Then you will see three "Automation IO" tabs, click on them and push the continuous data collector.

It is important to connect the cube because some functions (lights, temperature and tv) are executed only if the cube is connected.

How it works: VIDEO

Upload the code, insert the battery, close the box and...

...now you have a SMART CUBE!

I made a video to show you all the functions of the cube and how to use it.

Conclusions

This project is only the first step to a smart home. My purpose was to use the Arduino 101 board potentiality to create something new. I think that the accelerometer and gyroscope give to the board new opportunities in terms of mobility. With the BLE, in addition of being portable, is also easy to connect.

This is the fist time that I realize concretely one of my projects (I mean with a working prototype). It was hard and there were some difficulties during the road but at the end I've learn a lot and I'm happy with the result. I hope that also everyone who read this guide could learn something from my work and also modify this project on their needs. I'm sorry for my bad english but I hope that the images could help you.

In the future of this project I expect to create the centraline that is like the bridge between the smart cube and the actuators (lights, temperature, tv...). This centraline will receive the BLE signal from the cube and use this information to do smart things in your home.

I'm very happy to have the opportunity to use Arduino 101 and the Grove kit (the kit is very simple and fast for prototyping).

I hope that using the board in this way could be an inspiration for your project. You can personalize it as you want: I'm curious to see what functions will you create and in what different context you will use it!

Maybe this is not a revolution but it's a new way to interact with your home.

Hope you like this tutorial.

Now it's your turn: put your hands on the cube and hack it!

SMART CUBE: a new way to control your home!

Custom parts and enclosures

SMART CUBE box - Laser Cut
This is the file (.dxf) that you can upload on your laser cutter. I used a medium density fiberboard (MDF) of 3mm. Cut the black lines and engrave red lines. Important: if your material thickness is different you have to modify this sketch.
smart_cube_8sVCflFmhM.dxf
SMART CUBE box in .pdf
The same file of the box but in a different format: .pdf

Schematics

SMART CUBE - Fritzing schematics
This is a .jpeg of the Fritzing scheme (yellow wires are connected to Grove components)
Smart cube bb tfknaokws3
SMART CUBE - Grove Base Shield connections
This is a scheme of the connections in the Grove Shield
_cI0IwUsPVZ.Base shield connections

Code

SMART CUBE - complete code with commentsArduino
This is the code to upload on your Arduino 101. You can use this code as it is or customize based on your needs. Follow the comments to understand how it works.
// Libraries
#include "CurieIMU.h" // Acelerometer & Gyroscope
#include <CurieBLE.h> // Bluetooth Low Energy
#include <Wire.h>
#include "rgb_lcd.h"  // LCD
#include <Keypad.h>   // Keypad

rgb_lcd lcd; // LCD initialization

// Bluetooth initialization:
BLEPeripheral blePeripheral;                     // BLE Peripheral Device (the board you're programming)
// BLE Services
BLEService lightsService("1815");                // BLE Automation IO (1815) - lights informations
BLEService termoService("1815");                 // BLE Automation IO - temperature informations
BLEService TVService("1815");                    // BLE Automation IO - tv informations
// BLE characteristic
BLEUnsignedCharCharacteristic lightsChar("2A56", // BLE characteristic Digital (2A56)  - lights
    BLERead | BLENotify);
BLEUnsignedCharCharacteristic termoChar("2A56",  // BLE characteristic Digital - temperature
    BLERead | BLENotify);
BLEUnsignedCharCharacteristic TVChar("2A58",     // BLE characteristic Analog (2A58) - tv
    BLERead | BLENotify);

// Constant and variables declaration:

// Face orientation and shake functions:
int lastOrientation = - 1;              // previous orientation (for comparison)
unsigned long previousMillis = 0;       // last time update
unsigned long interval = 2000;          // time to wait in up position before the face activation
unsigned long SHAKEpreviousMillis = 0;  // last time update
unsigned long SHAKEinterval = 2000;     // time to wait during shaking for face deactivation
boolean keep = false;                   // this is used to count only one time the face orientation change
int lastFUNCTION = -1;                  // this is used to know what is the previous rientation

// Faces initilization: at the beginning every face is false
boolean face0 = false;
boolean face1 = false;
boolean face2 = false;
boolean face3 = false;
boolean face4 = false;
boolean face5 = false;

// LIGHTS face
const int LEDlights =  11;   // pin 11: yellow led

// TEMPERATURE face
const int pinTemp = A0;      // pin A0: temperature sensor
const int LEDhot =  12;      // pin 12: red led
const int LEDcold =  13;     // pin 13: blue led
float temperature;           // temperature value memorization
int B=3975;                  // B value of the thermistor
float resistance;            // resistance value memorization
float tooHot = 26.0;         // temperature at which the air conditioner is activated [SET]
float tooCold = 23.0;        // temperature at which the heater is activated [SET]

// TIMER face
int BUZZER = 3;              // pin 3: buzzer
boolean KEEPtime = false;    // this is used to count only one time the face orientation change (not restart while counting)
int TIMERmillis = 0;         // the following are for the countdown determination
int prevSHOWsecond = 0;
int CountdownInMillis = 0;
int SHOWmillis = 0;          // millis value calculation result
int SHOWminute = 0;          // minutes value to show in the monitor for the countdown
int SHOWseconds = 0;         // seconds value to show in the monitor for the countdown
const int SETminute =  2;    // set 2 minute timer [SET]
const int SETsecond =  30;   // set 30 seconds timer [SET]

// SOUND face
const int soundLED = 9 ;     // pin 9: green led    
const int soundSENSOR = A1;  // pin A0: sound sensor
int brightness = 0;          // green led brightness initialization

// TV face
const byte ROWS = 4;         // four rows keypad
const byte COLS = 3;         // three columns keypad
char keys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};                                  // keypad button values
byte rowPins[ROWS] = {10,8,7,6};    // pin 10,8,7,6: connect to the row pinouts of the keypad
byte colPins[COLS] = {5,4,2};       // pin 5,4,2: connect to the column pinouts of the keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );  // keypad initialization

// OFF face
const int LEDOFF =  A2;      // pin A2: red led


void setup() {

  pinMode(LEDlights, OUTPUT); // every led is set as an output
  pinMode(LEDhot, OUTPUT);
  pinMode(LEDcold, OUTPUT);
  pinMode(soundLED,OUTPUT);
  pinMode(LEDOFF, OUTPUT);
  
  Serial.begin(9600); // initialize Serial communication

  CountdownInMillis = (SETminute*60 + SETsecond)*1000; // this calculates the corrispondent value in millis from the minutes and seconds setting
  lcd.begin(16, 2);     // LCD initialization
  lcd.setRGB(0, 0, 0);  // LCD RGB is OFF at the beginning
  
  // initialize device
  Serial.println("Initializing IMU device...");
  CurieIMU.begin();

  // Set the accelerometer range to 2G
  CurieIMU.setAccelerometerRange(2);

  // Enable Shock Detection 
  CurieIMU.setDetectionThreshold(CURIE_IMU_SHOCK, 7000);  // 7.0g = 7000 mg  (this value set the intensity of the shock)
  CurieIMU.setDetectionDuration(CURIE_IMU_SHOCK, 2000);   // 2000ms (this value set the duration of the shock)
  CurieIMU.interrupts(CURIE_IMU_SHOCK);

  // BLE setup initialization
  blePeripheral.setLocalName("SmartCubeSketch");                 // the name of the project 
  
  blePeripheral.setAdvertisedServiceUuid(lightsService.uuid());  // add the lights service UUID
  blePeripheral.addAttribute(lightsService);                     // add the BLE lights service
  blePeripheral.addAttribute(lightsChar);                        // add the BLE lights characteristic
  lightsChar.setValue(3);                                        // initial value for this characteristic = 3
  //BLE lights value meaning: 0 = lights off, 1 = lights on, 3 = initial state, 4 = not used
  
  blePeripheral.setAdvertisedServiceUuid(termoService.uuid());   // add the temperature service UUID
  blePeripheral.addAttribute(termoService);                      // add the BLE temperature service
  blePeripheral.addAttribute(termoChar);                         // add the BLE temperature characteristic
  termoChar.setValue(0);                                         // initial value is 0: cold off - hot off
  //BLE termo value meaning: 0 = cold off - hot off, 1 = cold on - hot off, 2 = cold off - hot on, 3 = not used

  blePeripheral.setAdvertisedServiceUuid(TVService.uuid());      // add the tv service UUID
  blePeripheral.addAttribute(TVService);                         // add the BLE tv service
  blePeripheral.addAttribute(TVChar);                            // add the tv characteristic
  TVChar.setValue('x');                                          // initial value for this characteristic (x means nothing)
  //BLE TV  value meaning: #number corrispond to the pressed button, C: close TV, O: open TV, x: initial state

  blePeripheral.begin();
  Serial.println("Bluetooth device active, waiting for connections...");
  
} // setup end

void loop() {

  BLECentral central = blePeripheral.central(); // BLE connection
  
  unsigned long currentMillis = millis();       // current value of time in milliseconds

  // the following code comes from www.arduino.cc/en/Tutorial/Genuino101CurieIMUccelerometerOrientation
  // it is used to detect the orientation of the board
  int orientation = - 1;                        // the board's orientation
  String orientationString;                     // string for printing description of orientation
  
  // read accelerometer:
  int x = CurieIMU.readAccelerometer(X_AXIS);
  int y = CurieIMU.readAccelerometer(Y_AXIS);
  int z = CurieIMU.readAccelerometer(Z_AXIS);

  // calculate the absolute values, to determine the largest
  int absX = abs(x);
  int absY = abs(y);
  int absZ = abs(z);

  if ( (absZ > absX) && (absZ > absY)) {
    // base orientation on Z
    if (z > 0) {
      orientationString = "up";
      orientation = 0;  
    } else {
      orientationString = "down";
      orientation = 1;
    }
  } else if ( (absY > absX) && (absY > absZ)) {
    // base orientation on Y
    if (y > 0) {
      orientationString = "digital pins up";
      orientation = 2;
    } else {
      orientationString = "analog pins up";
      orientation = 3;
    }
  } else {
    // base orientation on X
    if (x < 0) {
      orientationString = "connector up";
      orientation = 4;
    } else {
      orientationString = "connector down";
      orientation = 5;
    }
  }
  // end of the tutorial code.
  // at this point you have the orientation value of the board constantly updated:
  /*
    The orientations of the board:
    0: flat, processor facing up     (TIMER)
    1: flat, processor facing down   (TV)
    2: landscape, analog pins down   (TEMPERATURE) 
    3: landscape, analog pins up     (OFF)
    4: portrait, USB connector up    (LIGHTS)
    5: portrait, USB connector down  (SOUND)
  */

  // for this project you need to know if the face has changed from the previous face function [lastFUNCTION != orientation]
  // but this information is printed only if the face is in the UP position for more than [interval] time
  // and only for one time [keep] (you don't nedd to constantly activate the face, you just need it one time)
  // because the orientation value is constantly updated you need to start counting time when the orientation change [orientation != lastOrientation]
  
  if (orientation != lastOrientation) {  // if the orientation has changed, start to count time
    lastOrientation = orientation;       // memorize the current orientation of the face
    previousMillis = currentMillis;      // memorize the time when the face has changed
    keep = false;                        
  } else if (currentMillis - previousMillis > interval && keep == false && lastFUNCTION != orientation) {
    //this condition print the orientation only if the face is up for an interval
    //and only for one time (keep)
    //and only if the face is different from the previous loop
    Serial.println(orientationString);   // print the orientation
    // the current face [orientation] is set as true (that means that the face function is set as activated)
    if (orientation == 1) {              // TV face
      face1 = true;                      // TV face becomes true
      lastFUNCTION = orientation;        // memorize this activation in [lastFUNCTION]
      Serial.println("TV true");         // print the activated face
      TVChar.setValue('O');              // O: open the tv signal (BLE): tv is open only one time
    }
    if (orientation == 4) {              // LIGHTS face
      face4 = true;                      
      lastFUNCTION = orientation;
      Serial.println("LIGHTS true");
    }
    if (orientation == 3) {              // OFF face
      face3 = true;
      lastFUNCTION = orientation;
      Serial.println("OFF true");
    }
    if (orientation == 5) {              // SOUND face
      face5 = true;
      lastFUNCTION = orientation;
      Serial.println("SOUND true");
    }
    if (orientation == 2) {             // TEMPERATURE face
      face2 = true;
      lastFUNCTION = orientation;
      Serial.println("TEMPERATURE true");
    }
    if (orientation == 0) {             // TIMER face
      face0 = true;
      lastFUNCTION = orientation;
      Serial.println("TIMER true");
      if (KEEPtime == false) {          // timer is activated only if it is the 1st cycle or has been stopped
        TIMERmillis = currentMillis;    // start counting time
      }
    }
    keep = true;  // [keep] change value so that, in the next loop, you can't enter in this condition if the face don't change (avoid to activate another time the same face)
  }

  // this condition is for the shake function: if you shake for more than [SHAKEinterval] time, the face is deactivated
  if (CurieIMU.getInterruptStatus(CURIE_IMU_SHOCK) && currentMillis - SHAKEpreviousMillis > SHAKEinterval) {
    Serial.println("SHAKE");               // print "SHAKE" if shake is detected 
    // the last activated face [lastFUNCTION] is set as false (that means that the face function is deactivated)
     
    //TV deactivation
    if (lastFUNCTION == 1) {                // TV face
      TVChar.setValue('C');                 // C: close the tv BLE signal
      Serial.println("TV false - CLOSE");   // print the closed face
      face1 = false;                        // TV face becomes false
    }
    //LIGHTS deactivation
    if (lastFUNCTION == 4) {                // LIGHTS face
      if (central.connected() == true) {    // if a central is connected to peripheral:
        lightsChar.setValue(0);             // lights OFF BLE signal
        digitalWrite (LEDlights, HIGH);     // open the yellow led to see the cube in the dark
      }
      Serial.println("LIGHTS false - CLOSE");
      face4 = false;                        // LIGHTS face become false
    }
    // OFF 
    if (lastFUNCTION == 3) {                // OFF face
      // OFF face shaked: everything is closed and red led OFF is open
      digitalWrite (LEDOFF, HIGH);          // red led OFF is on when cube is closed
      // now close all the activated functions:
      // CLOSE TV
      TVChar.setValue('C');                 // C: close the tv BLE signal
      Serial.println("TV false - CLOSE");
      face1 = false;
      // CLOSE LIGHTS
      Serial.println("LIGHTS false - CLOSE");
      if (central.connected() == true) {
        lightsChar.setValue(0); 
        digitalWrite (LEDlights, LOW);      // lights led is closed if OFF face is shaked
      }
      face4 = false;
      // CLOSE SOUND 
      analogWrite(soundLED, LOW);           // close the sound led
      Serial.println("SOUND false - CLOSE");
      face5 = false;
      //CLOSE TEMPERATURE
      if (central.connected() == true) {
        digitalWrite(LEDhot, LOW);
        digitalWrite(LEDcold, LOW);
        termoChar.setValue(0);              // temperature BLE signal: 0 = cold off - hot off
      }
      Serial.println("TEMPERATURE false - CLOSE");
      face2 = false;
      // CLOSE TIMER
      Serial.println("TIMER false - CLOSE");
      lcd.setRGB(0, 0, 0);                  // the LCD RGB is closed
      lcd.clear();
      KEEPtime = false;
      face0 = false;
      // The cube is inactive, only OFF led is active
      Serial.println("OFF false - CLOSE");
      face3 = false;                        // OFF face becomes false
    }
    // SOUND deactivation
    if (lastFUNCTION == 5) {                // SOUND face
      analogWrite(soundLED, LOW);           // close the sound led
      Serial.println("SOUND false - CLOSE");
      face5 = false;                        // SOUND face becomes false
    }
    // TEMPERATURE deactivation
    if (lastFUNCTION == 2) {                // TEMPERATURE face
      // if a central is connected to peripheral:
      if (central.connected() == true) {
        digitalWrite(LEDhot, LOW);          // close temperature red led 
        digitalWrite(LEDcold, LOW);         // close temperature blue led
        termoChar.setValue(0);              // temperature BLE signal: 0 = cold off - hot off
      }
      Serial.println("TEMPERATURE false - CLOSE");
      face2 = false;                        // TEMPERATURE face became false
    }
    // TIMER deactivation
    if (lastFUNCTION == 0) {                // TIMER face
      Serial.println("TIMER false - CLOSE");
      face0 = false;                        // TIMER face became false
      // if you shake the cube when the time is running, the LCD became red and show the remaining time to countdown
      lcd.setRGB(180, 40, 0);               // the RGB backlight become red
      lcd.clear(); // lcd is cleared
      lcd.setCursor(0, 0);
      lcd.print("STOP AT ");
      lcd.setCursor(8, 0);
      lcd.print(SHOWminute);                // indicates the minutes when you shake the cube
      lcd.setCursor(9, 0);
      lcd.print(":");
      lcd.setCursor(10, 0);
      lcd.print(SHOWseconds);               // indicates the seconds when you shake the cube
      tone(BUZZER,1000,1000);               // it make a short sound
      delay(2000);
      lcd.clear();                          // clear the LCD
      lcd.setRGB(0, 0, 0);                  // LCD RGB backlight is closed
      KEEPtime = false;                     // TIMER face became false
    }
      
    SHAKEpreviousMillis = currentMillis;    // memorize the value for the [SHAKEinterval] calculation
  }

  // the following instructions are executed in loop only if the face is activated

  if (face1 == true) {                      // TV face
    digitalWrite (LEDOFF, LOW);             // if this face is true the OFF face led is LOW 
    if (central.connected() == true) {      // if the cube is BLE connected 
      char key = keypad.getKey();           // read the value from the keypad
      if (key && orientation == 1){         // if something is pressed and only when the tv face is up (avoid involuntary keypad pression)
        if (key == '0') {                   // if the pressed key is 0
          TVChar.setValue(key);             // send the [key] value via BLE
          Serial.println(key);              // print the pressed button (comment if you don't want to show this information)
        }
        if (key == '1'){
          TVChar.setValue(key);
          Serial.println(key);
        }
        if (key == '2'){
          TVChar.setValue(key);
          Serial.println(key);
        }
        if (key == '3'){
          TVChar.setValue(key);
          Serial.println(key);
        }
        if (key == '4'){
          TVChar.setValue(key);
          Serial.println(key);
        }
        if (key == '5'){
          TVChar.setValue(key);
          Serial.println(key);
        }
        if (key == '6'){
          TVChar.setValue(key);
          Serial.println(key);
        }
        if (key == '7'){
          TVChar.setValue(key);
          Serial.println(key);
        }
        if (key == '8'){
          TVChar.setValue(key);
          Serial.println(key);
        }
        if (key == '9'){
          TVChar.setValue(key);
          Serial.println(key);
        }
        if (key == '*'){
          TVChar.setValue(key);
          Serial.println(key);
        }
        if (key == '#'){
          TVChar.setValue(key);
          Serial.println(key);
        }
      }
    }   
  }
    
  if (face4 == true) {                      // LIGHTS face
    digitalWrite (LEDOFF, LOW);             // if this face is true the OFF face led is LOW 
    if (central.connected() == true) {      // if a central is connected to peripheral:
      lightsChar.setValue(1);               // LIGHTS activated BLE signal
      digitalWrite (LEDlights, LOW);        // yellow led is closed because the home lights are on
    }
  }
    
  if (face3 == true) {                      // OFF face
    // when OFF face is up nothing is done 
    digitalWrite (LEDOFF, LOW);             // led OFF is activated only when the cube is shaked, so now is LOW
  }

    
  if (face5 == true) {                      // SOUND face
    digitalWrite (LEDOFF, LOW);             // if this face is true the OFF face led is LOW 
    // sound sensor is activated, led brightness regulated by the sond
    // this code comes from brightness regulation example
    long sum = 0;
    for (int i=0; i<32; i++) {
      sum += analogRead(soundSENSOR);
    }
    sum >>= 5;
    brightness = (sum*255)/1024;            // calculate the brightness value
    analogWrite(soundLED,brightness);       // green led brightness intensity is regulated by the noise
    delay(50) ;   
    //end brightness example
  }

    
  if (face2 == true) {                      // TEMPERATURE face
    digitalWrite (LEDOFF, LOW);             // if this face is true the OFF face led is LOW
    if (central.connected() == true) {      // if the cube is BLE connected 
      // read temperature value
      int val = analogRead(pinTemp);                               // get analog value
      resistance=(float)(1023-val)*10000/val;                      // get resistance
      temperature=1/(log(resistance/10000)/B+1/298.15)-273.15;     // calculate temperature
      //conditions of activation
      if (temperature > tooHot) {           // activate air conditioning
        digitalWrite(LEDhot, LOW);          // close heating led
        digitalWrite(LEDcold, HIGH);        // open air conditioner led
        termoChar.setValue(1);              // set via BLE the condition 1 = cold on - hot off
      }
      if (temperature < tooCold){           // activate heating
        digitalWrite(LEDhot, HIGH);
        digitalWrite(LEDcold, LOW);
        termoChar.setValue(2);              // 2 = cold off - hot on
      }
      if (temperature > tooCold && temperature < tooHot){  // ideal temperature: nothing is activated
        digitalWrite(LEDhot, LOW);
        digitalWrite(LEDcold, LOW);
        termoChar.setValue(0);              // 0 = cold off - hot off
      }
    }
  }


  if (face0 == true ) {                     // TIMER face activated
    digitalWrite (LEDOFF, LOW);             // if this face is true the OFF face led is LOW
    // this calculate the time to show in the display
    SHOWmillis = (CountdownInMillis - (currentMillis - TIMERmillis))/1000;
    SHOWminute = SHOWmillis/60;             // minutes value to show in the LCD
    SHOWseconds = SHOWmillis%60;            // seconds value to show in the LCD
    lcd.setRGB(50, 100, 70);                // open LCD with RGB blue color 
    if (prevSHOWsecond != SHOWseconds){     // refresh the screen every second (because refresh at every loop is too fast)
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("TIMER  ");
      lcd.setCursor(7, 0);
      lcd.print(SETminute);                 // writes the minutes that you set
      lcd.setCursor(8, 0);
      lcd.print(":");
      lcd.setCursor(9, 0);
      lcd.print(SETsecond);                 // writes the seconds that you set
      lcd.setCursor(0, 1);
      lcd.print(SHOWminute);                // write the current remaining minutes
      lcd.setCursor(1, 1);
      lcd.print(":");
      lcd.setCursor(2, 1);
      lcd.print(SHOWseconds);               // write the current remaining seconds
      KEEPtime = true;
      prevSHOWsecond = SHOWseconds;         // to refresh every second
    }
    if (SHOWminute == 0 && SHOWseconds == 0) {  // when countdown ends 
      lcd.clear();                          // clear the LCD
      lcd.setCursor(4, 0);
      lcd.setRGB(180, 40, 0);               // LCD RGB become red
      lcd.print("TIME OUT");
      tone(BUZZER,1000,500);                // three sounds
      delay (900);
      tone(BUZZER,1000,500);
      delay (900);
      tone(BUZZER,1000,1000);
      delay(1500);
      lcd.clear();                          // clear and close the LCD
      lcd.setRGB(0, 0, 0); 
      face0 = false;                        // TIMER face is now closed (false)
      KEEPtime = false;
    }
  }
  
} // loop end

Comments

Similar projects you might like

Arduino Obstacle Avoidance Robot with Ultrasonic HC-SR04

Project tutorial by Jorge Rancé

  • 304 views
  • 1 comment
  • 3 respects

Using Finite State Machines

by Gustavo Gonnet

  • 5,714 views
  • 2 comments
  • 16 respects

Alexa: "Your Clothes Are Dry"

Project in progress by TNunnster

  • 1,297 views
  • 0 comments
  • 5 respects

Temperature Streaming with Arduino + Big Data Tools

Project showcase by Gabriel Rodriguez

  • 1,277 views
  • 1 comment
  • 14 respects

How to Configure NeoPixels Using Vixen Lights and Arduino

Project tutorial by Victor Aguilar

  • 112 views
  • 0 comments
  • 3 respects

Bluetooth Speaker w/ Music-Reactive LED Matrix

Project tutorial by Modustrial Maker

  • 2,701 views
  • 0 comments
  • 7 respects
Add projectSign up / Login