An abstract overview of the system's operation (some details missing)
Last active
December 30, 2016 11:01
-
-
Save platisd/dce6760eb1aaaf2c6ff093c24352cb40 to your computer and use it in GitHub Desktop.
Pillbox docs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <RTClib.h> | |
#include <SoftwareSerial.h> | |
RTC_DS1307 rtc; | |
SoftwareSerial bluetooth(10, 11); // RX, TX | |
enum BoxState { | |
TIME_NOT_SET, // We are in this state when starting and no time has been set | |
TIME_SET_NOW_WAITING, // This is the normal operating state. Time is set and waiting to ring | |
RINGING // Ringing | |
}; | |
struct Alarm { | |
int hour; | |
int minute; | |
}; | |
const int numOfLids = 2; // How many lids we have | |
BoxState currentState[numOfLids] = {TIME_NOT_SET, TIME_NOT_SET}; | |
BoxState prevState[numOfLids] = {TIME_NOT_SET, TIME_NOT_SET}; | |
const int MAG_SWITCH[numOfLids] = {2, 3}; // Pins for magnetic switches for lid 1 and 2 | |
const boolean LID_OPEN = HIGH; | |
const boolean LID_CLOSED = LOW; | |
const int LED[numOfLids] = {4, 5}; // Led pins for lid 1 and 2 | |
const int BUZZER = 9; | |
boolean buzzerState [numOfLids] = {false, false}; | |
boolean alreadyRung [numOfLids] = {false, false}; | |
Alarm lid[numOfLids] = {{25, 61}, {25, 61}}; // Some initial bad values | |
unsigned long blinkFreq[numOfLids] = {0, 0}; // 0 indicates that led should be off, 1 constantly on and anything else is a frequency | |
unsigned long prevBlink[numOfLids] = {0, 0}; // The moment that the led was last blinked | |
boolean lidForgottenOpen[numOfLids] = {false, false}; | |
boolean ledState[numOfLids] = {false, false}; | |
boolean setAlarm[numOfLids] = {false, false}; | |
void setup() { | |
Serial.begin(9600); | |
bluetooth.begin(9600); | |
for (int i = 0; i < numOfLids; i++) { | |
pinMode(LED[i], OUTPUT); | |
pinMode(MAG_SWITCH[i], INPUT); | |
digitalWrite(MAG_SWITCH[i], HIGH); // Set the internal pullups | |
} | |
pinMode(BUZZER, OUTPUT); | |
if (!rtc.begin()) { | |
Serial.println("Couldn't find RTC"); | |
while (1); //block the execution | |
} | |
// Set the time for the first time if the clock is NOT running | |
if (!rtc.isrunning()) { | |
// following line sets the RTC to the date & time this sketch was compiled | |
rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); | |
} else { | |
DateTime now = rtc.now(); | |
Serial.print("Current time: "); | |
Serial.print(now.hour()); | |
Serial.print(":"); | |
Serial.println(now.minute()); | |
} | |
} | |
void loop() { | |
if (bluetooth.available()) { | |
// We are expecting a string in the form of Hour:Minute,Hour:Minute* | |
// * is the package delimiter | |
String input = bluetooth.readStringUntil('*'); | |
String lidInput[2]; | |
lidInput[0] = input.substring(0, input.indexOf(",")); | |
lidInput[1] = input.substring(input.indexOf(",") + 1); | |
for (int i = 0; i < numOfLids; i++) { | |
lid[i].hour = lidInput[i].substring(0, lidInput[i].indexOf(":")).toInt(); | |
lid[i].minute = lidInput[i].substring(lidInput[i].indexOf(":") + 1).toInt(); | |
setAlarm[i] = lid[i].hour <= 24; // if time is set correctly it will be a valid hour | |
} | |
} | |
for (int i = 0; i < numOfLids; i++) { | |
switch (currentState[i]) { | |
case TIME_NOT_SET: | |
if (isAlarmSet(i)) { | |
setState(i, TIME_SET_NOW_WAITING); | |
blinkFreq[i] = 0; // Keep the led continuously OFF | |
} else { | |
blinkFreq[i] = 1; // Keep the led continuously ON | |
} | |
break; | |
case TIME_SET_NOW_WAITING: | |
if (isLidOpen(i)) { // We should not have an open lid in this state | |
blinkFreq[i] = 1000; // Blink the led every 1 sec to indicate that lid should close | |
} else { | |
lidForgottenOpen[i] = false; // Indicate that lid is not (forgotten) open | |
setBuzzer(i, LOW); // Make sure buzzer not ringing if lid is closed (and kept ringing due to a lid forgotten open) | |
blinkFreq[i] = 0; // The LED shouldn't be blinking if the lid is shut (unless it's time to open which is determined later) | |
} | |
if (isTimeToOpen(i) && !alreadyRung[i]) { // Ring only if it is time and we have not already rung in the same minute | |
blinkFreq[i] = 300; // Blink the led 3 times per sec to indicate that lid should open | |
setBuzzer(i, HIGH); // Start ringing the buzzer | |
setState(i, RINGING); // Set state to RINGING | |
alreadyRung[i] = true; // So to make sure we don't ring again during the same minute if the user shuts the lid | |
if (isLidOpen(i)) { // If it is time to open and the lid is already open, then it's probably forgotten | |
lidForgottenOpen[i] = true; | |
} | |
} else { // If it isn't time to open and the lid is closed then the led shouldn't be blinking | |
if (!isTimeToOpen(i)) { | |
alreadyRung[i] = false; // If it is not time to ring, then we definitely have not already rung | |
} | |
} | |
break; | |
case RINGING: | |
if (isLidOpen(i)) { // If lid is open then we should stop ringing | |
if (!lidForgottenOpen[i]) { | |
setBuzzer(i, LOW); // Stop ringing the buzzer only if the lid wasn't forgotten open | |
} | |
setState(i, TIME_SET_NOW_WAITING); // Go back to previous state | |
} | |
break; | |
default: // We should never be here | |
break; | |
} | |
} | |
blinkLeds(); | |
} | |
/** | |
lidID: The relevant lid | |
newState: The state that the related lid wants to set the buzzer | |
Tries to turn buzzer ON or OFF but only if both lids agree on the state | |
*/ | |
void setBuzzer(int lidID, boolean newState) { | |
buzzerState[lidID] = newState; | |
boolean result = false; | |
// The state of the buzzer is determined by the combination of the states | |
// that the different lids want to set it. If one lid wants to set it HIGH | |
// then it should be able to. But if a lid wants to set the buzzer LOW then | |
// it should only go low if all of the lids agree on it. This is done in case | |
// a lid starts the buzzer, then the other lid starts the buzzer as well, but | |
// the buzzer should be turned off when BOTH of the lids are shut. | |
for (int i = 0; i < numOfLids; i++) { | |
result = result || buzzerState[i]; | |
} | |
digitalWrite(BUZZER, result); | |
} | |
/** | |
Blink the leds according to the frequency set in the blinkFreq array | |
*/ | |
void blinkLeds() { | |
for (int i = 0; i < numOfLids; i++) { | |
if (blinkFreq[i] > 1) { // the led should blink at the specified frequency | |
unsigned long currentTime = millis(); | |
if (currentTime >= prevBlink[i] + blinkFreq[i]) { | |
prevBlink[i] = currentTime; | |
setLed(i, !ledState[i]); // Set the led to the opposite state than it currently is | |
} | |
} else { // Led should be off if the freq is 0 or on if freq is 1 | |
setLed(i, (blinkFreq[i] == 1)); | |
} | |
} | |
} | |
/** | |
@param lidID: The related LED (the lidID matches the related lid) | |
@param newState: The new state for the LED | |
Set the specifiied led to the supplied state and log down the current state | |
*/ | |
void setLed(int lidID, boolean newState) { | |
ledState[lidID] = newState; // Save the current led state | |
digitalWrite(LED[lidID], newState); | |
} | |
/** | |
@param lidID: The related lid | |
@param newState: The new state for the lid to be set | |
Saves the old state and sets the new | |
*/ | |
void setState(int lidID, BoxState newState) { | |
prevState[lidID] = currentState[lidID]; | |
currentState[lidID] = newState; | |
} | |
/** | |
@param lidID: The related lid | |
@return Whether the alarm for the related lid has been set | |
Checks if the alarm for the specified lid is set | |
*/ | |
boolean isAlarmSet(int lidID) { | |
return setAlarm[lidID]; | |
} | |
/** | |
@param lidID: The related lid | |
@return Whether the specified lid is open | |
Checks if the specified lid is open | |
*/ | |
boolean isLidOpen(int lidID) { | |
return digitalRead(MAG_SWITCH[lidID]) == LID_OPEN; | |
} | |
/** | |
@param lidID: The related lid | |
@return Wether it is time to open the related lid | |
Checks if it is time for the user to open the specified lid | |
*/ | |
boolean isTimeToOpen(int lidID) { | |
DateTime now = rtc.now(); | |
return now.hour() == lid[lidID].hour && now.minute() == lid[lidID].minute; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment