49713 Designing for the Internet of Things
· 16 members
A hands-on introductory course exploring the Internet of Things and connected product experiences.
Found in DIoT - Augmented Objects · UNLISTED (SHOWN IN POOLS)
Khansa's Enchanted Sketchbook connects her with her husband across the world through short, endearing audio messages that play out of her glowing sketchbook.
With the advent of different voice and video calling apps, we are able to easily connect with each other. However, these applications and platforms (i.e. texts or video call) don’t necessarily help communicate emotions genuinely. For example, one may want to tell their significant other or close friend who is away an endearing message like “I love you”, or “I miss you, hope your day is going well”. Texting or video calling may not translate the message to be as special as it was intended. This is where our Enchanted Book helps communicate short, endearing messages to one's significant other or close friends/family in such a way that lifts the receiver's spirits.
This was the problem faced by one of our users interviewed. Khansa is currently located in Pakistan, separated from her husband who is studying at Carnegie Mellon University. When interviewed about home-objects that she would want to be enchanted (connected to the internet to display ambient information), she was drawn to her sketchbook. Both her and her husband sketch daily. With a simple object she uses frequently, enchanting this could help the distance seem less. Our problem statement was as follows:
How might we enchant Khansa's notebook to connect with her significant other abroad?
We plan to enchant this everyday object, a sketchbook, to give it an additional ability to send and receive meaningful, short, endearing messages when she interacts with it on the norm, while still maintaining its basic functionality. We also wanted to emphasize the ambience of the device for Khansa so it wouldn't be obtrusive or distracting, but rather catch her eye when there was a message.
A list of key functionalities:
The first iteration of this enchanted book was prototyped with cardboard for form and had the basic functionalities working: Glowing when a message was received and playing a tone from a piezometer when the book was opened. This prototype helped us understand how the circuit and the form would come together and also provided a lot of opportunities for improvement.
Below are pictures of the first prototyped circuit (Note: the DFPlayer Mini does not work in this iteration, the piezometer takes its place)
In this iteration, we incorporated classmates feedback and tailored it more towards Khansa instead of marketing it to anyone. It was a big jump from our initial prototype. We added additional features we believed were necessary to really make this enchanted book as usable as possible where it gets the full experience across.
We added:
Main Circuit:
(All features)
Recording and Sending Circuit
(Record and send features)
Speaker Circuit
(Play the audio message when called)
We successfully enchanted Khansa's sketchbook to glow when she receives a message from her husband, with the ability to save the message, and then proceed to record and send a message. The following demonstration shows the functionality of the three circuits together and each of the buttons in the book.
//Created by Langley V, Swapnil A, and Ussama N on 11/17/2019
//Creative Project II
//Last edited: 11-26-2019
// This #include statement was automatically added by the Particle IDE.
#include <DFPlayer.h>
DFPlayer dfPlayer;
int folder = 0;
int volume = 0;
bool powerOn = false;
//********************************************************************
//Neopixel
//********************************************************************
// This #include statement was automatically added by the Particle IDE.
#include <neopixel.h>
//Set pixel pin, number of pins, and type
#define PIXEL_PIN D2
#define PIXEL_COUNT 7
#define PIXEL_TYPE WS2812
const uint8_t KEYFRAMES[] = {
// Rising
20, 21, 22, 24, 26, 28, 31, 34, 38, 41, 45, 50, 55, 60, 66, 73, 80, 87, 95,
103, 112, 121, 131, 141, 151, 161, 172, 182, 192, 202, 211, 220, 228, 236,
242, 247, 251, 254, 255,
// Falling
254, 251, 247, 242, 236, 228, 220, 211, 202, 192, 182, 172, 161, 151, 141,
131, 121, 112, 103, 95, 87, 80, 73, 66, 60, 55, 50, 45, 41, 38, 34, 31, 28,
26, 24, 22, 21, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
};
int keyframePointer = 0;
int numKeyframes = sizeof(KEYFRAMES) - 1;
//define neopixel strip
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);
//Global variable delcaration
//int timeDuration;
//Declare booleans that go along with the message received from the sender
bool displayNotif = false; //calendar event boolean
bool isRunning = false;
long timeStartedAt = -1;
int timeElapsed = -1;
//Define colorOff: 0,0,0
uint32_t colorOff = strip.Color( 0, 0, 0 );
//********************************************************************
//Publishing Events
//********************************************************************
// This value will store the last time we published an event
long lastPublishedAt = 0;
int last_published = -1;
//********************************************************************
//Flex Sensor
//********************************************************************
int flexPin = A0;
int flexReading = 0;
//********************************************************************
//LED indicator
//********************************************************************
//int ledPin = A1;
int RedPin = D5; //To identify the state of the RED Button
int GreenPin = D3; //To identify the state of the GREEN Button
int YellowPin = D4; //To identify the state of the YELLOW Button
int BluePin = D6; //To identify the state of the BLUE Button
int RedButton = A1; //For recording the Message
int GreenButton = A2; //For sending the Message
int YellowButton = A3; //For saving the Message
int BlueButton = A4; //For listening to the Message
int publishAfter = 10000;
//High = 1;
int RedButtonState = 0;
int GreenButtonState = 0;
int YellowButtonState = 0;
int BlueButtonState = 0;
bool messageExists = false;
int PreviousRBS = 0;
bool messageHeared = false;
int here = 0;
void setup() {
//another event starts, stop current event and then reset timer, then start over.
Particle.function("startNotif", startNotif);
Particle.function("endNotif", endNotif);
//Code initialization
strip.begin();
strip.show();
//strip.setBrightness(30); //dim lights
//get time particle io started at
timeStartedAt = millis();
//initial color, Yellow glow
uint32_t c = strip.Color(0, 255, 255);
//reset all the colors
for (int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, c);
delay(100);
}
strip.show();
for (int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, colorOff);
delay(100);
}
strip.show();
//********************************************************************
//Declare pin modes for flex, speaker and LED
pinMode(flexPin, INPUT);
pinMode( RedButton , INPUT_PULLUP ); // sets pin as input
pinMode( GreenButton , INPUT_PULLUP); // sets pin as input
pinMode( YellowButton , INPUT_PULLUP); // sets pin as input
pinMode( BlueButton , INPUT_PULLUP); // sets pin as input
pinMode( RedPin , OUTPUT ); // sets pin as output
pinMode( GreenPin , OUTPUT ); // sets pin as output
pinMode( YellowPin , OUTPUT ); // sets pin as output
pinMode( BluePin , OUTPUT ); // sets pin as output
dfPlayer.setLogging(true);
volume = dfPlayer.getVolume();
delay(5000);
Particle.variable("force", flexReading);
Particle.subscribe("swapnil/2019/enchantedBook/" , handleSharedEvent);
Particle.subscribe("langley/2019/iot/enchantedBookMessage/" , handleSharedEventSpeaker);
Particle.variable("RedState", RedButtonState);
Particle.variable("PreviousRBS", PreviousRBS);
Particle.variable("GreenState", GreenButtonState);
Particle.variable("BlueButtonState", BlueButtonState);
Particle.variable("Here", here);
Particle.variable("force", flexReading);
Particle.variable("folder", folder);
Particle.variable("volume", volume);
Particle.variable("power", powerOn);
Particle.function("setVolume", setVolume);
Particle.function("playFolder", playFolder);
Particle.function("setPower", setPower);
setVolume("20");
setPower("true");
folder = 1;
delay(200);
//dfPlayer.playTrack(1);
PlayMessage();
delay(1000);
//playFolder(String(folder));
}
void loop() {
//Get flex sensor reading
flexReading = analogRead(flexPin);
//delay(100);
RedButtonState = digitalRead( RedButton );
GreenButtonState = digitalRead( GreenButton );
YellowButtonState = digitalRead( YellowButton );
BlueButtonState = digitalRead( BlueButton );
//Recording the Message
if( PreviousRBS == HIGH && RedButtonState == LOW)
{
//Start recording
digitalWrite( RedPin, HIGH); // turn the LED On
PreviousRBS = RedButtonState;
messageExists = true;
}
else if(PreviousRBS == LOW && RedButtonState == HIGH)
{
//Stop recording
digitalWrite( RedPin, LOW); // turn the LED Off
}
PreviousRBS = RedButtonState;
//Sending the Message
if( GreenButtonState == LOW && messageExists == true )
{
digitalWrite(GreenPin, HIGH);
delay(100);
digitalWrite(GreenPin, LOW);
SendMessage();
delay(2000);
// delay for a bit
messageExists = false;
}
else
{
digitalWrite( GreenPin, LOW);
}
//If there is a message waiting, go into this loop
if(displayNotif) {
//CASE 1: GLOW
//If there is a message and the flex sensor is bent (book is closed)
if(flexReading > 700) {
for (int i = 0; i < strip.numPixels(); i++) {
uint8_t color = (127 * KEYFRAMES[keyframePointer]) / 256;
strip.setPixelColor(i, 0, 0, color);
}
strip.show();
// Increment the keyframe pointer.
if (++keyframePointer > numKeyframes) {
// Reset to 0 after the last keyframe.
keyframePointer = 0;
}
}
//CASE 2: PLAY MESSAGE
//There is a notification and the book is opened
else if(flexReading < 700) {
//LED glows because there is a message
digitalWrite( BluePin, HIGH);
//delay(1000);
// delay(100);
// PlayMessage();
// delay(4000);
// digitalWrite( BluePin, LOW);
//Play message
if(BlueButtonState == LOW )
{
Particle.publish("bluebutton", "low-prev-high");
here = 1;
PlayMessage();
delay(100);
displayNotif = false;
messageHeared = true;
digitalWrite( BluePin, LOW);
}
//Set notification back to false, message has been heard
//displayNotif = false;
isRunning = false;
for (int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, 0, 0, 0);
}
strip.show();
//digitalWrite( BluePin, LOW);
}
else {
//do nothing
//return;
}
}
// NO message, do nothing
else {
//do nothing
}
//Save the Message
if(YellowButtonState == LOW && messageHeared == true)
{
// store the time when you last published
int last_published = -1;
digitalWrite(YellowPin, HIGH);
delay(500);
SaveMessage();
messageHeared = false;
}
else
{
digitalWrite( YellowPin, LOW);
}
delay(500);
}
//Particle Functions that change boolean value to true or false
//For now, have console "send the message" to this particle board that there is a message
//Next steps: Use another particle board to publish an event and use this particle board to receive it
bool startNotif(String val) {
//if it is not running then start it
if (!isRunning) {
//timeStartedAt = millis(); //reset time
displayNotif = true;
isRunning = true;
//goes into loop and runs light code
}
//A calendar event ambient notification is already running
else {
//Stop what is happening
//turn all off
for (int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, colorOff);
delay(50);
}
strip.show();
}
}
//End the message notification
bool endNotif(String val) {
//turn all off
for (int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, colorOff);
delay(50);
}
strip.show();
//no ambient notification
displayNotif = false;
//code is not running
isRunning = false;
}
void SendMessage()
{
// Remember that a device can publish at rate of about 1 event/sec,
// with bursts of up to 4 allowed in 1 second.
// Back to back burst of 4 messages will take 4 seconds to recover.
// So we want to limit the amount of publish events that happen.
// check that it's been 10 secondds since our last publish
if( lastPublishedAt + publishAfter < millis() )
{
// Remember our subscribe is matching "db2018/paired/"
// We'll append the device id to get more specific
// about where the event came from
// System.deviceID() provides an easy way to extract the device
// ID of your device. It returns a String object of the device ID,
// which is used to identify your device.
String eventName = "langley/2019/iot/sendenchantedBookMessage/" + System.deviceID();
// now we have something like "diot/2019/paired/0123456789abcdef"
// and that corresponds to this devices info
// then we share it out
Particle.publish( eventName, "Message_Sent" );
// And this will get shared out to all devices using this code
// we just pubished so capture this.
lastPublishedAt = millis();
}
}
//Notify other person
void ReceivedMessage()
{
// Remember that a device can publish at rate of about 1 event/sec,
// with bursts of up to 4 allowed in 1 second.
// Back to back burst of 4 messages will take 4 seconds to recover.
// So we want to limit the amount of publish events that happen.
// check that it's been 10 secondds since our last publish
if( lastPublishedAt + publishAfter < millis() )
{
// Remember our subscribe is matching "db2018/paired/"
// We'll append the device id to get more specific
// about where the event came from
// System.deviceID() provides an easy way to extract the device
// ID of your device. It returns a String object of the device ID,
// which is used to identify your device.
String eventName = "langley/2019/iot/receivedenchantedBookMessage/" + System.deviceID();
// now we have something like "diot/2019/paired/0123456789abcdef"
// and that corresponds to this devices info
// then we share it out
Particle.publish( eventName, "Message_Sent" );
// And this will get shared out to all devices using this code
// we just pubished so capture this.
lastPublishedAt = millis();
}
}
//Write data to spreadsheet
void SaveMessage() {
// check if 1 minute has elapsed
if( last_published + 10000 < millis() ){
Particle.publish( "messageLogged", String("Hi-I-love-youuuu") );
last_published = millis();
}
}
//
int playFolder(String buffer) {
folder = atoi(buffer);
// the following commands play 6 tracks that were stored in the root folder of the TFCard
// the dfPlayer.playTrack method uses DFPlayer command 0x03
// The tracks were named 001 - 006.
// The tracks were added to the TFCard in the following sequence 001, 002, 003, 005, 004, and 006
// This code plays the tracks in order 001 - 006
delay(3000);
dfPlayer.playTrack(1);
delay(3000);
dfPlayer.playTrack(2);
delay(7000);
return 0;
}
void PlayMessage()
{
// Remember that a device can publish at rate of about 1 event/sec,
// with bursts of up to 4 allowed in 1 second.
// Back to back burst of 4 messages will take 4 seconds to recover.
// So we want to limit the amount of publish events that happen.
// check that it's been 10 second since our last publish
if( lastPublishedAt + publishAfter < millis() )
{
// Remember our subscribe is matching "db2018/paired/"
// We'll append the device id to get more specific
// about where the event came from
// System.deviceID() provides an easy way to extract the device
// ID of your device. It returns a String object of the device ID,
// which is used to identify your device.
String eventName = "langley/2019/iot/playMessage/" + System.deviceID();
// now we have something like "diot/2019/paired/0123456789abcdef"
// and that corresponds to this devices info
// then we share it out
Particle.publish( eventName, "Message_Sent" );
// And this will get shared out to all devices using this code
// we just pubished so capture this.
lastPublishedAt = millis();
}
}
void handleSharedEvent(const char *event, const char *data)
{
// Now we're getting ALL events published using "db2018/paired/"
// This includes events from this device.
// So we need to ignore any events that we sent.
// Let's check the event name
String eventName = String( event ); // convert to a string object
// This gives us access to a bunch of built in methods
// Like indexOf()
// Locates a character or String within another String.
// By default, searches from the beginning of the String,
// but can also start from a given index,
// allowing for the locating of all instances of the character or String.
// It Returns: The index of val within the String, or -1 if not found.
// We can use this to check if our event name contains the
// id of this device
String deviceID = System.deviceID();
// device id = 0123456789abcdef
// event = "diot/2019/paired/0123456789abcdef"
if( eventName.indexOf( deviceID ) != -1 ){
// if we get anything other than -1
// the event came from this device.
// so stop doing stuff
return;
}
displayNotif = true;
delay(1000);
ReceivedMessage();
}
void handleSharedEventSpeaker(const char *event, const char *data)
{
// Now we're getting ALL events published using "db2018/paired/"
// This includes events from this device.
// So we need to ignore any events that we sent.
// Let's check the event name
String eventName = String( event ); // convert to a string object
// This gives us access to a bunch of built in methods
// Like indexOf()
// Locates a character or String within another String.
// By default, searches from the beginning of the String,
// but can also start from a given index,
// allowing for the locating of all instances of the character or String.
// It Returns: The index of val within the String, or -1 if not found.
// We can use this to check if our event name contains the
// id of this device
String deviceID = System.deviceID();
// device id = 0123456789abcdef
// event = "diot/2019/paired/0123456789abcdef"
if( eventName.indexOf( deviceID ) != -1 ){
// if we get anything other than -1
// the event came from this device.
// so stop doing stuff
return;
}
digitalWrite(GreenPin, HIGH);
delay(200);
digitalWrite(GreenPin, LOW);
delay(200);
}
// setVolume is a Particle method that can be used to adjust volume via the Particle Console
int setVolume(String buffer) {
volume = atoi(buffer);
dfPlayer.setVolume(volume);
return 0;
}
// setPower is a Particle method that that plays a gong when power is toggled false, and chirping birds when power is toggned true
bool setPower(String buffer) {
if ((buffer[0] == 'f') && (powerOn == true)) {
powerOn = false;
dfPlayer.playFolderTrack(1,2);
}
if ((buffer[0] == 't') && (powerOn == false)) {
powerOn = true;
dfPlayer.playFolderTrack(1,1);
}
return powerOn;
}
Click to Expand
//For Receiving and Sending Circuit
int RedPin = D4; //To identify the state of the RED Button
int GreenPin = D5; //To identify the state of the GREEN Button
int RedButton = A5; //For recording the Message
int GreenButton = A0; //For sending the Message
long lastPublishedAt = 0; //The last time an event was published
int publishAfter = 10000;// Time delay before publishing a new event
//Initial state of the button
int RedButtonState=1;
int GreenButtonState=1;
int PreviousRBS = 1;
bool MessageExists = false;
void setup()
{
// Set Button pins as input
pinMode( RedButton , INPUT_PULLUP );
pinMode( GreenButton , INPUT_PULLUP);
Particle.variable("Message",RedButtonState); //to verify the state of the red button used for recording message
// Set LED pins as output
pinMode( RedPin , OUTPUT );
pinMode( GreenPin , OUTPUT );
//Subscribe to Langley's event to get feedback if my published event has been received
Particle.subscribe( "langley/2019/iot/receivedenchantedBookMessage/" , handleSharedEvent );
}
void loop()
{
//Read the state of the button
RedButtonState = digitalRead( RedButton );
GreenButtonState = digitalRead( GreenButton );
//Recording the Message
if( PreviousRBS == HIGH && RedButtonState == LOW)
{
//Start recording
digitalWrite( RedPin, HIGH); // turn the LED On
//message = "This is a Sample Message"; //Sample text to simulate voice recording
MessageExists = true;
}
else if(PreviousRBS == LOW && RedButtonState == HIGH)
{
//Stop recording
digitalWrite( RedPin, LOW); // turn the LED Off
}
//Sending the Message
if( GreenButtonState == LOW && MessageExists == true)
{
publishMyEvent();
delay(100);
digitalWrite(GreenPin, HIGH);
MessageExists = false;
}
else
{
digitalWrite(GreenPin, LOW);
}
//saving the message
PreviousRBS = RedButtonState;
}
void publishMyEvent()
{
// Remember that a device can publish at rate of about 1 event/sec,
// with bursts of up to 4 allowed in 1 second.
// Back to back burst of 4 messages will take 4 seconds to recover.
// So we want to limit the amount of publish events that happen.
// check that it's been 10 secondds since our last publish
if( lastPublishedAt + publishAfter < millis() )
{
// Remember our subscribe is matching "db2018/paired/"
// We'll append the device id to get more specific
// about where the event came from
// System.deviceID() provides an easy way to extract the device
// ID of your device. It returns a String object of the device ID,
// which is used to identify your device.
String eventName = "swapnil/2019/enchantedBook/" + System.deviceID();
// now we have something like "diot/2019/paired/0123456789abcdef"
// and that corresponds to this devices info
// then we share it out
Particle.publish( eventName, "Swapnil_Message" );
// And this will get shared out to all devices using this code
// we just pubished so capture this.
lastPublishedAt = millis();
}
}
// Our event handlde requires two bits of information
// This gives us:
// A character array that consists of the event name
// A character array that contains the data published in the event we're responding to.
void handleSharedEvent(const char *event, const char *data)
{
// Now we're getting ALL events published using "db2018/paired/"
// This includes events from this device.
// So we need to ignore any events that we sent.
// Let's check the event name
String eventName = String( event ); // convert to a string object
// This gives us access to a bunch of built in methods
// Like indexOf()
// Locates a character or String within another String.
// By default, searches from the beginning of the String,
// but can also start from a given index,
// allowing for the locating of all instances of the character or String.
// It Returns: The index of val within the String, or -1 if not found.
// We can use this to check if our event name contains the
// id of this device
String deviceID = System.deviceID();
// device id = 0123456789abcdef
// event = "diot/2019/paired/0123456789abcdef"
if( eventName.indexOf( deviceID ) != -1 ){
// if we get anything other than -1
// the event came from this device.
// so stop doing stuff
return;
}
// otherwise do your stuff to respond to
// the paired device here
digitalWrite( GreenPin, HIGH);
delay(500);
digitalWrite( GreenPin, LOW);
delay(500);
digitalWrite( GreenPin, HIGH);
delay(500);
digitalWrite( GreenPin, LOW);
delay(500);
}
Click to Expand
//For DFPlayer ONLY
//Plays audio file on it
#include "DFPlayer.h"
// global variables
DFPlayer dfPlayer;
int folder = 0;
int volume = 0;
bool powerOn = false;
bool playMessage = false;
// This value will store the last time we published an event
long lastPublishedAt = 0;
// this is the time delay before we should publish a new event
// from this device
int publishAfter = 10000;
void setup() {
Particle.subscribe("langley/2019/iot/playMessage/" , handleSharedEvent );
Particle.variable("playMessage", playMessage);
Particle.variable("folder", folder);
Particle.variable("volume", volume);
Particle.variable("power", powerOn);
Particle.function("setVolume", setVolume);
Particle.function("playFolder", playFolder);
Particle.function("setPower", setPower);
Serial.begin(115200);
Serial1.begin(9600);
delay(5000);
// the following command tells the program to display data on the serial console.
// logging can be turned on and off at will throughout the user's code
dfPlayer.setLogging(true);
volume = dfPlayer.getVolume();
setVolume("20");
setPower("true");
folder = 1;
delay(200);
//playFolder(String(folder));
delay(1000);
dfPlayer.playTrack(1);
}
void loop() {
if( playMessage == true ){
// otherwise do your stuff to respond to
// the paired device here
//playFolder(String(folder));
dfPlayer.playTrack(1);
publishMyEvent();
playMessage = false;
delay( 5000 );
}
}
// playFolder is a Particle Function ... that can be run from the Particle Console ..
int playFolder(String buffer) {
folder = atoi(buffer);
// the following commands play 6 tracks that were stored in the root folder of the TFCard
// the dfPlayer.playTrack method uses DFPlayer command 0x03
// The tracks were named 001 - 006.
// The tracks were added to the TFCard in the following sequence 001, 002, 003, 005, 004, and 006
// This code plays the tracks in order 001 - 006
delay(3000);
dfPlayer.playTrack(1);
delay(3000);
return 0;
}
// setVolume is a Particle method that can be used to adjust volume via the Particle Console
int setVolume(String buffer) {
volume = atoi(buffer);
dfPlayer.setVolume(volume);
return 0;
}
// setPower is a Particle method that that plays a gong when power is toggled false, and chirping birds when power is toggned true
bool setPower(String buffer) {
if ((buffer[0] == 'f') && (powerOn == true)) {
powerOn = false;
dfPlayer.playFolderTrack(1,2);
}
if ((buffer[0] == 't') && (powerOn == false)) {
powerOn = true;
dfPlayer.playFolderTrack(1,1);
}
return powerOn;
}
// Our event handlde requires two bits of information
// This gives us:
// A character array that consists of the event name
// A character array that contains the data published in the event we're responding to.
void handleSharedEvent(const char *event, const char *data)
{
// Now we're getting ALL events published using "db2018/paired/"
// This includes events from this device.
// So we need to ignore any events that we sent.
// Let's check the event name
String eventName = String( event ); // convert to a string object
// This gives us access to a bunch of built in methods
// Like indexOf()
// Locates a character or String within another String.
// By default, searches from the beginning of the String,
// but can also start from a given index,
// allowing for the locating of all instances of the character or String.
// It Returns: The index of val within the String, or -1 if not found.
// We can use this to check if our event name contains the
// id of this device
String deviceID = System.deviceID();
// device id = 0123456789abcdef
// event = "diot/2019/paired/0123456789abcdef"
if( eventName.indexOf( deviceID ) != -1 ){
// if we get anything other than -1
// the event came from this device.
// so stop doing stuff
return;
}
playMessage = true;
}
void publishMyEvent()
{
// Remember that a device can publish at rate of about 1 event/sec,
// with bursts of up to 4 allowed in 1 second.
// Back to back burst of 4 messages will take 4 seconds to recover.
// So we want to limit the amount of publish events that happen.
// check that it's been 10 secondds since our last publish
if( lastPublishedAt + publishAfter < millis() )
{
// Remember our subscribe is matching "db2018/paired/"
// We'll append the device id to get more specific
// about where the event came from
// System.deviceID() provides an easy way to extract the device
// ID of your device. It returns a String object of the device ID,
// which is used to identify your device.
String eventName = "langley/2019/iot/enchantedBookMessage/" + System.deviceID();
// now we have something like "diot/2019/paired/0123456789abcdef"
// and that corresponds to this devices info
// then we share it out
Particle.publish( eventName, "From_Langley" );
// And this will get shared out to all devices using this code
// we just pubished so capture this.
lastPublishedAt = millis();
}
}
Click to Expand
The next steps and future scope would include the following:
There were many challenges that arose in the code.
Firstly, the DFPlayer would not play the single audio track on the microSD card, even though everything was wired correctly for an Particle Argon (Note - there is code for a DFPlayer, but it is either for Arduino or a Particle Photon). It turns out that we were using a faulty breadboard that did not connect the speaker correctly to the Argon. We also discovered that using only the 3.3V power supply on the Argon would not power the DFPlayer, Neopixels, LED's and pushbuttons. Hence, the use of three separate circuits that communicated through Particle.publish events. Later on, the speaker itself had very weak connections (however, no more small speakers were available for replacements), and only worked in certain positions.
Secondly, we attempted to code the logic for the case that if the book was already open and the user receives a message. We ran into multiple issues trying to use previous and current state and a time duration variable and it taking 10 seconds per if-statement to decide what to do for each loop. We overcame this issue by having the book owner press the blue button when they want to hear the message.
Conclusions: Our team was able to complete a working prototype with three Particle boards communicating with each other seamlessly. We are satisfied with what we accomplished. We were able to share a video demonstration with Khansa herself, and she really loved what we put together.
None of the original resources worked for the DFPlayer Mini. We relied on a customized diagram provided by our professor that is incorporated into the Fritzing diagrams above.
Tutorials on: https://diotlabs.daraghbyrne.me/
Good reference anyways - For a Particle Photon Board and using no libraries
This project is only listed in this pool. Be considerate and think twice before sharing.
A hands-on introductory course exploring the Internet of Things and connected product experiences.
Khansa's Enchanted Sketchbook connects her with her husband across the world through short, endearing audio messages that play out of her glowing sketchbook.
November 25th, 2019