Katie Kristoff
Published

Hackster Live March 2017 Workshop

Learn to voice control LEDs using Web Bluetooth and Arduino/Genuino 101.

BeginnerFull instructions provided1 hour2,444
Hackster Live March 2017 Workshop

Things used in this project

Hardware components

Arduino 101
Arduino 101
×1
Arduino UNO Click Shield
MikroE Arduino UNO Click Shield
Optional for extension project
×1
RELAY click
MikroE RELAY click
Optional for extension project
×1
LED (generic)
LED (generic)
×2
Breadboard (generic)
Breadboard (generic)
×1
Jumper wires (generic)
Jumper wires (generic)
×3
Resistor 330 ohm
Resistor 330 ohm
×2
USB-A to B Cable
USB-A to B Cable
×1

Software apps and online services

Arduino IDE
Arduino IDE
AWS S3
Amazon Web Services AWS S3
Web Bluetooth API
annyang voice recognition
Font Awesome
Github

Story

Read more

Schematics

LED Circuit

Code

Lend me your ears Code

Arduino
#include <CurieBLE.h>
/**
 * Example demonstrating the use of the relay click and arduino uno click shield from
 * MikroElektronika.
 * 
 * Uplaod this sketch to your arduino/genuino101, complete the circuit and access from the web!
 * Web Bluetoooth goodness!
 * 
 * To be added:
 *    2) BLE control. Done
 *    3) relay object. Done
 *    4) relay interval function. Done
 *    5) RTC "alarm clock" function. Yet to be done . . .
 */

/**
 * pins for each relay specified here. 
 * depend on the Arduino click shield specifications, with the relay click board 
 * plugged into slot 1
 */
#define RELAY1 6 
#define RELAY2 10

/**
 * The Relay object will model the relay state and help with control flow in the loop()
 * function.
 */

class Relay
{

  int relayID;
  int pinAssignment;
  boolean relayState;
  boolean intervalState;
  long interval;
  boolean intervalToggle;

  public:

  Relay(int id, int pin )
  {
    relayID = id;
    pinAssignment = pin;
    relayState = false;  
    intervalState = false;
    interval = 0;
    intervalToggle = false;
  }

  /*
   * The relay is initialized to the physical pin assigned to it and 
   * this pin is set to low.
   * Not the relay intial states are set in the relay constructor.
   */
  void initialize()
  {
    pinMode( pinAssignment, OUTPUT);
    digitalWrite(pinAssignment,LOW);
  }
  
  int getRelayID() {return relayID;}
  void setRelayId(int id) {relayID = id;}

  int getPinAssignment() {return pinAssignment;}
  void setPinAssignment(int pin) {pinAssignment = pin;}

  boolean getRelayState() {return relayState;}
  void setRelayState(boolean state ) {relayState = state;}

  boolean getIntervalState() {return intervalState;}
  void setIntervalState(boolean state) { intervalState = state;}

  long getInterval(){return interval;}
  void setInterval(long i) {interval = i;}

  boolean getIntervalToggle() {return intervalToggle;}
  void setIntervalToggle(boolean tog){intervalToggle = tog;}

  void toggle() 
  { 
    intervalToggle = !intervalToggle;
    digitalWrite(pinAssignment, intervalToggle);
  }

  void turnOn()
  {
    digitalWrite(pinAssignment,HIGH);
  }

  void turnOff()
  {
    digitalWrite(pinAssignment,LOW);
  }

};

Relay relay1(1, RELAY1);
Relay relay2(2, RELAY2);

// timing parameters
long currentMillis, previousMillisRelay1, previousMillisRelay2;

union
{
  long interval;
  unsigned char bytes[4];  
} relaySettings;

/* establish BLE service & characteristics */
BLEPeripheral blePeripheral;
BLEService relayService("917649A0-D98E-11E5-9EEC-0002A5D5C51B");
BLECharacteristic relayCharacteristic("917649A1-D98E-11E5-9EEC-0002A5D5C51B", BLEWrite, 5);
// BLEUnsignedCharCharacteristic relayCharacteristic("917649A1-D98E-11E5-9EEC-0002A5D5C51B", BLERead | BLEWrite);
BLEDescriptor relayDescriptor("2902","relay");

void setup() 
{
  // initiate serial communications for debugging
  Serial.begin(9600);
  Serial.println("click relay example");
 /** 
   *  BLE initilizations
   */

  blePeripheral.setLocalName("relays");
  blePeripheral.setAdvertisedServiceUuid(relayService.uuid());
  blePeripheral.addAttribute(relayService);
  blePeripheral.addAttribute(relayCharacteristic);
  blePeripheral.addAttribute(relayDescriptor);

  blePeripheral.setEventHandler(BLEConnected, blePeripheralConnectHandler);
  blePeripheral.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);
  relayCharacteristic.setEventHandler(BLEWritten, relayCharacteristicWritten);
  
  // All BLE characteristics should be initialized to a starting value prior
  // using them.

  const unsigned char relayInitializer[5] = {0,0,0,0,0};
  relayCharacteristic.setValue(relayInitializer,5);
  
  blePeripheral.begin();
  
  // Set relays to initial states
  relay1.initialize();
  relay2.initialize();

  // intialize timing paramters
  currentMillis = millis();
  previousMillisRelay1 = millis();
  previousMillisRelay2 = millis();
  
}

void loop() 
{
  /**
   * The main loop() checks for the relays being set to intervals and
   * toggles then is so and the interval is exceeded.
   */

  currentMillis = millis();
  
  if (relay1.getIntervalState()) 
  {
    if ((currentMillis - previousMillisRelay1) > relay1.getInterval())
    {
      relay1.toggle();
      previousMillisRelay1 = currentMillis;
      Serial.println("toggle1");
    }
  }

  if (relay2.getIntervalState())
  {  
    if ((currentMillis - previousMillisRelay2) > relay2.getInterval())
    {
      relay2.toggle();
      previousMillisRelay2 = currentMillis;
      Serial.println("toggle2");
    }
  }
  
}

void blePeripheralConnectHandler(BLECentral& central) 
{
  // central connected event handler
  Serial.print("Connected event, central: ");
  Serial.println(central.address());
}

void blePeripheralDisconnectHandler(BLECentral& central) 
{
  // central disconnected event handler
  Serial.print("Disconnected event, central: ");
  Serial.println(central.address());
}

void relayCharacteristicWritten(BLECentral& central, BLECharacteristic& characteristic)
{
  /**
   * This function is called whenever the user changes the relayCharacteristic on the hybrid
   * web app. It is used to chage the state of the relay object, these changes are then
   * checked for in the loop. 
   * Why? Well if we wished to simply turn the relays off and on, this approach is unnecessary. 
   * we could just simply turn the relays off and on in the swtch/case statement. However
   * we would like to add other functionality to the relays, such as interval on/off timing.
   * Since we have 2 relays we can;t use the CurieTImer library, it has only one timer and we may
   * wish to have different timing intervals for each relay. Addtionally this approach will allow
   * us to more easily extend this app to many relays, which is is more realisitc for
   * a home automation system.
   */
  const unsigned char* relayData = relayCharacteristic.value();
  
  relaySettings.bytes[0] = relayData[4];
  relaySettings.bytes[1] = relayData[3];
  relaySettings.bytes[2] = relayData[2];
  relaySettings.bytes[3] = relayData[1];

  // convert interval byte array to long by casting;
  long interval = (long)relaySettings.interval;
  switch(relayData[0])
  {
    case 0:
      // 0 value, do nothing
      Serial.print(relayData[0]);
      Serial.print(" written ");Serial.print("interval: ");Serial.println(interval);
      break;
    case 1:
      // relay 1 selected
      Serial.print("relay1: ");Serial.print(relayData[0]);Serial.print(" interval: ");Serial.println(interval);
      if (interval != 0) 
      {
        relay1.setIntervalState(true);
        relay1.setRelayState(true);
        relay1.setInterval(interval);
      } else {
        if (relay1.getRelayState()) 
        { 
          relay1.setRelayState(false); 
          relay1.turnOff(); 
          relay1.setIntervalState(false);
          relay1.setInterval(0); 
        }
        else {
          relay1.setRelayState(true); 
          relay1.turnOn();
          relay1.setIntervalState(false);
          relay1.setInterval(0);
        }       
      }
      break;
    case 2:
      // relay 2 selected
      Serial.print("relay2: ");Serial.print(relayData[0]);Serial.print(" interval: ");Serial.println(interval);
      if (interval != 0) 
      {
        relay2.setIntervalState(true);
        relay2.setRelayState(true);
        relay2.setInterval(interval);
      } else {
        if (relay2.getRelayState()) 
        { 
          relay2.setRelayState(false); 
          relay2.turnOff(); 
          relay2.setIntervalState(false);
          relay2.setInterval(0); 
        }
        else {
          relay2.setRelayState(true); 
          relay2.turnOn();
          relay2.setIntervalState(false);
          relay2.setInterval(0);
        }       
      }
      break;     
  }
}  

Credits

Katie Kristoff

Katie Kristoff

4 projects • 126 followers
Educator and enthusiastic crafter.
Thanks to Greg V..

Comments