MoritzDornseifer
Published © GPL3+

IoT Cloud Enabled Alarm Clock

Set your alarm via Arduino's IoT Cloud and start your day right on time.

IntermediateShowcase (no instructions)9,009
IoT Cloud Enabled Alarm Clock

Things used in this project

Story

Read more

Code

Code for IoT Alarm Clock

Arduino
/*
  Sketch generated by the Arduino IoT Cloud Thing "Alarm_Clock"
  https://create.arduino.cc/cloud/things/...

  Arduino IoT Cloud Properties description

  The following variables are automatically generated and updated when changes are made to the Thing properties

  int alarmHour;
  int gmt;
  String wifi_time;
  int alarmMinute;
  int readClockMaxValue;

  Properties which are marked as READ/WRITE in the Cloud Thing will also have functions
  which are called when their values are changed from the Dashboard.
  These functions are generated with the Thing and added at the end of this sketch.
*/

#include "thingProperties.h"

//OLED example
/******************************************************************************
   MicroOLED_Demo.ino
   SFE_MicroOLED Library Demo
   Jim Lindblom @ SparkFun Electronics
   Original Creation Date: October 27, 2014

   This sketch uses the MicroOLED library to draw a 3-D projected
   cube, and rotate it along all three axes.

   Development environment specifics:
    Arduino 1.0.5
    Arduino Pro 3.3V
    Micro OLED Breakout v1.0

   This code is beerware; if you see me (or any other SparkFun employee) at the
   local, and you've found our code helpful, please buy us a round!

   Distributed as-is; no warranty is given.
 ******************************************************************************/

// wifi rtc
/**********************************************************
  MKR1000 - MKR WiFi 1010 - MKR VIDOR 4000 WiFi RTC

  This sketch asks NTP for the Linux epoch and sets the internal Arduino MKR1000's RTC accordingly.

  created 08 Jan 2016
  by Arturo Guadalupi <a.guadalupi@arduino.cc>

  modified 26 Sept 2018

  http://arduino.cc/en/Tutorial/WiFiRTC
  This code is in the public domain.
*/



//pins

/*5-pin jst
  black "RET" -> HV side (Logic Level Converter) -> D10 OUTPUT to arm alarm PIN RET_SET
  brown "SET" -> HV side (Logic Level Converter) -> D10 OUTPUT to arm alarm PIN RET_SET
  red -> "GND" -> (source)
  orange -> "6V" -> (source)
  yellow -> "ALARM" -> x
*/
#define RET_SET 10 //black and brown wire on jst 5 connector

/* 7-pin-jst
  black -> x
  brown -> x
  red -> GND
  orange -> x
  yellow -> D9 -> INPUT from button on backside PIN jst_7_yellow
  green -> D8 -> OUTPUT to arm and engage alarm PIN jst_7_green
  blue -> x - used to be battery voltage. if provided 3.3v terrible things happen
*/

#define jst_7_green 8 // green OUTPUT to arm and engage alarm
#define jst_7_yellow 9 //yellow INPUT from button on backside

/* clock / motor driver
  BI1 -> D11
  BI2 -> D12
  Em (Emitter) on clock for predefined position -> A0 PIN EM
*/
#define BI1 11
#define BI2 12
#define read_clock A0

/* 2-pin-jst
  blue -> 3.3V Input
  red -> D7 INPUT reads snooze button PIN snooze
*/
#define snooze 7 //snooze button on top

/* o-led
  GND
  3.3V
  SDI -> SDA i2c  A4
  SCK -> SCL i2c  A5
  RST -> D6 OLED reset PIN PIN_RESET
*/
#define PIN_RESET 6 //OLED reset

/* front panel
  red -> 3.3V Input
  black -> GND Input
  yellow -> D5 INPUT Button sleep PIN sleep | PLUG IN ORANGE CABLE FROM FRONT PANEL
  orange -> D4 INPUT Button Alarm armed pressed PIN arm_alarm | PLUG IN YELLOW CABLE FROM BUTTON BOARD
*/
#define arm_alarm 4 //button from small front panel
#define sleep 5 //button sleep on front panel


//alarm in tivoli
boolean alarm_armed = false;
boolean alarm_engaged = false;

boolean last_button_state;
unsigned long millis_when_button_was_not_pressed;
unsigned long millis_when_display_was_lit = 0;
boolean display_on = false;

unsigned long button_press_duration = 800; // milliseconds button is held down when pressing it


//clock

unsigned long epoch;
unsigned long millis_of_last_epoch;
int millis_until_next_epoch = 300000; //five minutes

int displayedMinute = 0;
int displayedHour = 0;


unsigned long millis_pin_status_clocks_hands = millis();

int pin_status_clocks_hands = 1;
bool clock_in_predefined_position = false; //true if clock is displaying 12:00 at 12:00

int read_clock_value_for_predefined_position = 370; //test with ac/dc power supply was 312, 302, 305, 270, 387, 400 ..

bool clock_looking_for_reference_position = true;

bool stay_in_reference_position = true;
unsigned long millis_staying_in_reference_position = millis();

bool set_time_button_was_pressed = false;

//int times to do the math
int minuteNow = 0;
int hourNow = 0;

//int alarmMinute = 0; now as cloud property
//int alarmHour = 6; now as cloud property


//OLED

#include <Wire.h>  // Include Wire if you're using I2C
#include <SFE_MicroOLED.h>  // Include the SFE_MicroOLED library

#define DC_JUMPER 1 //like in hardware setup on board, position of solder jumper
//reset defined above
/*
   A5 - SCL
   A4 - SDA
*/
MicroOLED oled(PIN_RESET, DC_JUMPER);    // I2C declaration


//wifi real time clock

#include <RTCZero.h>

RTCZero real_time_clock;


void setup()
{
  // Initialize serial and wait for port to open:
  Serial.begin(9600);
  // This delay gives the chance to wait for a Serial Monitor without blocking if none is found
  delay(1500);

  // Defined in thingProperties.h
  initProperties();

  // Connect to Arduino IoT Cloud
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);

  /*
     The following function allows you to obtain more information
     related to the state of network and IoT Cloud connection and errors
     the higher number the more granular information you’ll get.
     The default is 0 (only errors).
     Maximum is 4
  */
  setDebugMessageLevel(2);
  ArduinoCloud.printDebugInfo();

  delay(10000); //necessary for serial routine to run see https://forum.arduino.cc/index.php?topic=605436.0

  pinMode(LED_BUILTIN, OUTPUT);

  //tivoli and arduino pins

  /*5-pin jst
    black "RET" -> HV side (Logic Level Converter) -> D10 OUTPUT to arm alarm PIN RET_SET
    brown "SET" -> HV side (Logic Level Converter) -> D10 OUTPUT to arm alarm PIN RET_SET
    red -> "GND" -> (source)
    orange -> "6V" -> (source)
    yellow -> "ALARM" -> x
  */
  pinMode(RET_SET, OUTPUT);

  /* 7-pin-jst
    black -> x
    brown -> x
    red -> GND
    orange -> x
    yellow -> D9 -> INPUT from button on backside PIN jst_7_yellow
    green -> D8 -> OUTPUT to arm and engage alarm PIN jst_7_green
    blue -> x - used to be battery voltage. if provided 3.3v terrible things happen
  */
  pinMode(jst_7_yellow, INPUT); //INPUT Set Alarm from Button on backside, analog 0 if button is pressed
  pinMode(jst_7_green, OUTPUT);

  /* 2-pin-jst
    blue -> 3.3V Input
    red -> D7 INPUT reads snooze button PIN snooze
  */
  pinMode(snooze, INPUT); //reads snooze button

  /* clock / motor driver
    BI1 -> D11
    BI2 -> D12
    Em (Emitter) on clock for predefined position -> A0 PIN read_clock
  */
  pinMode(BI1, OUTPUT);
  pinMode(BI2, OUTPUT);
  pinMode(read_clock, INPUT);

  digitalWrite(BI1, LOW);
  digitalWrite(BI2, LOW);

  /* o-led
    GND
    3.3V
    SDI -> SDA i2c  A4
    SCK -> SCL i2c  A5
    RST -> D6 OLED reset PIN PIN_RESET
  */
  //PIN_RESET used in oled library

  /* front panel
    red -> 3.3V Input
    black -> GND Input
    yellow -> D3 INPUT Button Alarm armed pressed PIN arm_alarm | PLUG IN YELLOW CABLE FROM BUTTON BOARD
    orange -> D2 INPUT Button sleep PIN sleep | PLUG IN ORANGE CABLE FROM FRONT PANEL
  */

  pinMode(arm_alarm, INPUT); //INPUT Button Alarm armed pressed | PLUG IN GREAY CABLE FROM BUTTON BOARD
  pinMode(sleep, INPUT); //reads sleep button


  //oled

  oled.begin();    // Initialize the OLED
  oled.clear(ALL); // Clear the display's internal memory
  oled.clear(PAGE); // Clear the buffer.

  //oled.setFontType(1);
  //oled.flipHorizontal(1);
  //oled.flipVertical(1);
  

  //wifi rtc

  real_time_clock.begin();

  readClockMaxValue=0;

  setRTC(); // get time/epoch from ntp server


  //setup complete
  print_text("Hallo");


}

void loop()
{
  ArduinoCloud.update();
  // Your code here


  //get time

  minuteNow = real_time_clock.getMinutes();
  hourNow = real_time_clock.getHours() + gmt;
  
  if (hourNow > 23)
  {
    hourNow = hourNow - 24;
  }

  wifi_time = String(hourNow) + ":" + String(minuteNow);
  
  if ((millis_of_last_epoch + millis_until_next_epoch) <= millis()) //get new time/epoch
  {
    setRTC();
  }
  

  //for debugging
  //Serial.println(wifi_time);

  if(analogRead(read_clock) > readClockMaxValue)
  {
    readClockMaxValue = analogRead(read_clock);
  }


  //set off alarm
  //if alarm time == time now AND alarm is armed
  if (((minuteNow >= alarmMinute) && ((minuteNow <= alarmMinute + 4 )) && (alarmHour == hourNow)) && (alarm_armed == true))
  {

    //show alarm time
    if (alarm_engaged == false && display_on == false)
    {
      millis_when_display_was_lit = millis(); //display will light up
    }

    alarm_engaged = true;
  }
  else
  {
    alarm_engaged = false;
  }


  //check if displayed time in clock is equal to time
  if (analogRead(read_clock) >= read_clock_value_for_predefined_position)
  {
    clock_in_predefined_position = true;
    digitalWrite(LED_BUILTIN, HIGH);

    if (clock_looking_for_reference_position == true)
    {
      clock_looking_for_reference_position = false;
      displayedMinute = 0;

      if (hourNow < 12)
      {
        displayedHour = 0;
      }
      else
      {
        displayedHour = 12;
      }
      
      //stay in reference position for two seconds
      stay_in_reference_position = true;
      millis_staying_in_reference_position = millis();

    }

  }
  else
  {
    clock_in_predefined_position = false;
    digitalWrite(LED_BUILTIN, LOW);
  }


  //check if clock is on time
  if (hourNow == 12 && minuteNow == 0)
  {
    if (clock_in_predefined_position == false)
    {
      readClockMaxValue = 0;
      clock_looking_for_reference_position = true;
    }
  }

  //stay in reference position for two seconds
  if(stay_in_reference_position == true and millis() - millis_staying_in_reference_position >= 2000)
  {
    stay_in_reference_position = false;
  }

  //move clock's hands if necessary
  if (clock_looking_for_reference_position == true)
  {
    move_clocks_hand();
  }
  else
  {
    if (stay_in_reference_position == false)
    {
      //if displayed time is five minutes (or less) early, wait for it, else, move hands
      if(((displayedHour*60+displayedMinute) < (hourNow*60+minuteNow)) || ((displayedHour*60+displayedMinute) > (hourNow*60+minuteNow+5)))
      {
        move_clocks_hand();
      }
    }
  }

  /*
    //set clock manually
    if (digitalRead(jst_7_yellow) == HIGH)
    {

    }
  */


  //set alarm time
  //if button is pressed to change wake up time at least for press duration
  if (digitalRead(snooze) == HIGH)
  {
    //turn on display or keep it on respectively (display is already on when alarm is engaged)
    millis_when_display_was_lit = millis(); //turns on display

    //if wake up time is displayed and button is pressed again
    if ((display_on == true) && (last_button_state == 0))
    {
      //change wake up time
      alarmMinute = alarmMinute + 5;
    }

    //if wake up time is displayed and button still pressed
    else if ((display_on == true) && (millis() >= millis_when_button_was_not_pressed + button_press_duration) && (millis() < millis_when_button_was_not_pressed + 3 * button_press_duration))
    {
      //change wake up time
      alarmMinute = alarmMinute + 5;
    }

    //if wake up time is displayed and button is pressed for over three turns, speed up wake up time count
    else if ((display_on == true) && (millis() >= millis_when_button_was_not_pressed + 3 * button_press_duration) && (millis() < millis_when_button_was_not_pressed + 6 * button_press_duration))
    {
      //change wake up time
      alarmMinute = alarmMinute + 15;
    }

    //if wake up time is displayed and button is pressed for over six turns, speed up wake up time count even more
    else if ((display_on == true) && (millis() >= millis_when_button_was_not_pressed + 6 * button_press_duration))
    {
      //change wake up time
      alarmMinute = alarmMinute + 30;
    }

    //weck_Minute = alarmMinute; weck_minute renamed to alarmMinute


  } // if button is pressed (sleep button also changes wake up time)
  else
  {
    millis_when_button_was_not_pressed = millis(); //to determine how long button is held down from when it wasn't pressed yet
  }

  //track last button state (snooze)
  last_button_state = digitalRead(snooze);

  if (alarmMinute >= 60)
  {
    alarmMinute = 0;
    alarmHour = alarmHour + 1;

    if (alarmHour == 24)
    {
      alarmHour = 0;
    }

    //weck_Stunde = alarmHour; weck_Stunde renamed to alarmHour

  }


  //display alarm time
  if ((millis() - millis_when_display_was_lit) <= 4000)
  {
    display_alarm_time();
  }
  else
  {
    stop_displaying_alarm_time();
  }


  //arm alarm
  //if alarm is armed (button is pressed)
  if (digitalRead(arm_alarm) == HIGH) //button pressed to arm alarm
  {

    //show alarm time
    if (alarm_armed == false && display_on == false)
    {
      millis_when_display_was_lit = millis(); //display will light up
    }

    alarm_armed = true;
  }
  else if (digitalRead(arm_alarm) == LOW)
  {
    alarm_armed = false;
  }


  //play radio or not according to alarm settings

  digitalWrite(jst_7_green, HIGH);
  digitalWrite(RET_SET, HIGH);

  if (alarm_armed == true && alarm_engaged == false) // don't play radio, waiting for alarm to engage
  {
    digitalWrite(jst_7_green, LOW);
    digitalWrite(RET_SET, LOW);
  }

}


void display_alarm_time()
{
  //display wake up time

  oled.setFontType(3); // max font 5 columns 1 row
  oled.flipHorizontal(1);
  oled.flipVertical(1);

  oled.setCursor(0, 0);  // Set the text cursor to the upper-left of the screen.
  if (alarmHour < 10)
  {
    oled.print("0");
    oled.print(alarmHour);
  }
  else
  {
    oled.print(alarmHour);
  }

  oled.print(":");      // Print ":"

  if (alarmMinute < 10)
  {
    oled.print("0");
    oled.print(alarmMinute);
  }
  else
  {
    oled.print(alarmMinute);
  }

  oled.display();

  display_on = true;

}

void stop_displaying_alarm_time()
{
  oled.clear(ALL); // Clear the display's internal memory
  oled.clear(PAGE); // Clear the buffer.
  display_on = false;
}

void print_text(String text)
{

  oled.setFontType(1); // max font 5 columns 1 row
  oled.flipHorizontal(1);
  oled.flipVertical(1);

  oled.setCursor(0, 0);  // Set the text cursor to the upper-left of the screen.

  oled.print(text);

  oled.display();

  delay(5000); //display for 5 seconds

  oled.clear(ALL); // Clear the display's internal memory
  oled.clear(PAGE); // Clear the buffer.

}

void move_clocks_hand()
{
  //millis_pin_status_clocks_hands defaults millis in setup
  //BI1, BI2 default LOW in setup

  if (millis() >= millis_pin_status_clocks_hands + 100)
  {
    //pin_status_clocks_hands defaults to 1
    switch (pin_status_clocks_hands)
    {
      case 1:
        {
          pin_status_clocks_hands = 2;
          digitalWrite(BI1, HIGH);
          digitalWrite(BI2, LOW);
        }
        break;
      case 2:
        {
          pin_status_clocks_hands = 3;
          digitalWrite(BI1, LOW);
          digitalWrite(BI2, LOW);
        }
        break;
      case 3:
        {
          pin_status_clocks_hands = 4;
          digitalWrite(BI1, LOW);
          digitalWrite(BI2, HIGH);
        }
        break;
      case 4:
        {
          pin_status_clocks_hands = 1;
          digitalWrite(BI1, LOW);
          digitalWrite(BI2, LOW);

          displayedMinute++;

          if (displayedMinute == 60)
          {
            displayedHour = displayedHour + 1;
            displayedMinute = 0;
          }
          if (displayedHour == 24)
          {
            displayedHour = 0;
          }
        }
        break;
    }
    millis_pin_status_clocks_hands = millis();
  }
}




void onGmtChange() {
  // Do something
}


void onAlarmMinuteChange() {
  // Do something
}


void onAlarmHourChange() {
  // Do something
}



void setRTC() {
  
  epoch = WiFi.getTime();
  
  real_time_clock.setEpoch(epoch);
  
  millis_of_last_epoch = millis();

  
}

Credits

MoritzDornseifer

MoritzDornseifer

0 projects • 1 follower

Comments